From 05466e99ce2ec19750ba9373116bfbc07e69ae55 Mon Sep 17 00:00:00 2001 From: Mark Baker Date: Fri, 11 Jun 2021 17:29:49 +0200 Subject: [PATCH] Html import dimension conversions (#2152) Allows basic column width conversion when importing from Html that includes UoM... while not overly-sophisticated in converting units to MS Excel's column width units, it should allow import without errors Also provides a general conversion helper class, and allows column width getters/setters to specify a UoM for easier usage --- CHANGELOG.md | 5 +- docs/topics/recipes.md | 49 +++++++++ phpstan-baseline.neon | 22 +--- src/PhpSpreadsheet/Helper/Dimension.php | 103 ++++++++++++++++++ src/PhpSpreadsheet/Reader/Html.php | 9 +- src/PhpSpreadsheet/Shared/Drawing.php | 56 +++++----- src/PhpSpreadsheet/Shared/Font.php | 2 +- src/PhpSpreadsheet/Shared/Xls.php | 8 +- .../Worksheet/ColumnDimension.php | 22 +++- src/PhpSpreadsheet/Worksheet/RowDimension.php | 20 +++- .../Helper/DimensionTest.php | 72 ++++++++++++ .../Reader/Html/HtmlTest.php | 20 +++- .../Shared/DrawingTest.php | 80 ++++++++++++++ .../Worksheet/ColumnDimensionTest.php | 10 ++ .../Worksheet/RowDimensionTest.php | 55 ++++++++++ 15 files changed, 464 insertions(+), 69 deletions(-) create mode 100644 src/PhpSpreadsheet/Helper/Dimension.php create mode 100644 tests/PhpSpreadsheetTests/Helper/DimensionTest.php create mode 100644 tests/PhpSpreadsheetTests/Shared/DrawingTest.php create mode 100644 tests/PhpSpreadsheetTests/Worksheet/RowDimensionTest.php diff --git a/CHANGELOG.md b/CHANGELOG.md index 82289a0b..4825193a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). - Support for passing flags in the Reader `load()` and Writer `save()`methods, and through the IOFactory, to set behaviours. [PR #2136](https://github.com/PHPOffice/PhpSpreadsheet/pull/2136) - See [documentation](https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-and-writing-to-file/) for details - More flexibility in the StringValueBinder to determine what datatypes should be treated as strings [PR #2138](https://github.com/PHPOffice/PhpSpreadsheet/pull/2138) +- Helper class for conversion between css size Units of measure (`px`, `pt`, `pc`, `in`, `cm`, `mm`). [PR #2152](https://github.com/PHPOffice/PhpSpreadsheet/issues/2145) +- Allow Row height and Column Width to be set using different units of measure (`px`, `pt`, `pc`, `in`, `cm`, `mm`), rather than only in points or MS Excel column width units. [PR #2152](https://github.com/PHPOffice/PhpSpreadsheet/issues/2145) ### Changed @@ -27,7 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org). ### Fixed -- Nothing. +- Column width and Row height styles in the Html Reader when the value includes a unit of measure. [Issue #2145](https://github.com/PHPOffice/PhpSpreadsheet/issues/2145). + ## 1.18.0 - 2021-05-31 diff --git a/docs/topics/recipes.md b/docs/topics/recipes.md index 8854e55e..471d1dda 100644 --- a/docs/topics/recipes.md +++ b/docs/topics/recipes.md @@ -1122,6 +1122,16 @@ A column's width can be set using the following code: $spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(12); ``` +If you want to set a column width using a different unit of measure, +then you can do so by telling PhpSpreadsheet what UoM the width value +that you are setting is measured in. +Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches), +`cm` (centimeters) and `mm` (millimeters). + +```php +$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(120, 'pt'); +``` + If you want PhpSpreadsheet to perform an automatic width calculation, use the following code. PhpSpreadsheet will approximate the column with to the width of the widest column value. @@ -1207,6 +1217,16 @@ Excel measures row height in points, where 1 pt is 1/72 of an inch (or about 0.35mm). The default value is 12.75 pts; and the permitted range of values is between 0 and 409 pts, where 0 pts is a hidden row. +If you want to set a row height using a different unit of measure, +then you can do so by telling PhpSpreadsheet what UoM the height value +that you are setting is measured in. +Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches), +`cm` (centimeters) and `mm` (millimeters). + +```php +$spreadsheet->getActiveSheet()->getRowDimension('10')->setRowHeight(100, 'pt'); +``` + ## Show/hide a row To set a worksheet''s row visibility, you can use the following code. @@ -1560,6 +1580,20 @@ Default column width can be set using the following code: $spreadsheet->getActiveSheet()->getDefaultColumnDimension()->setWidth(12); ``` +Excel measures column width in its own proprietary units, based on the number +of characters that will be displayed in the default font. + +If you want to set the default column width using a different unit of measure, +then you can do so by telling PhpSpreadsheet what UoM the width value +that you are setting is measured in. +Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches), +`cm` (centimeters) and `mm` (millimeters). + +```php +$spreadsheet->getActiveSheet()->getDefaultColumnDimension()->setWidth(400, 'pt'); +``` +and PhpSpreadsheet will handle the internal conversion. + ## Setting the default row height Default row height can be set using the following code: @@ -1568,6 +1602,21 @@ Default row height can be set using the following code: $spreadsheet->getActiveSheet()->getDefaultRowDimension()->setRowHeight(15); ``` +Excel measures row height in points, where 1 pt is 1/72 of an inch (or +about 0.35mm). The default value is 12.75 pts; and the permitted range +of values is between 0 and 409 pts, where 0 pts is a hidden row. + +If you want to set a row height using a different unit of measure, +then you can do so by telling PhpSpreadsheet what UoM the height value +that you are setting is measured in. +Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches), +`cm` (centimeters) and `mm` (millimeters). + +```php +$spreadsheet->getActiveSheet()->getDefaultRowDimension()->setRowHeight(100, 'pt'); +``` + + ## Add a GD drawing to a worksheet There might be a situation where you want to generate an in-memory image diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index 4d4f7193..d41411de 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -2487,7 +2487,7 @@ parameters: - message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" - count: 4 + count: 2 path: src/PhpSpreadsheet/Reader/Html.php - @@ -4100,11 +4100,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Date.php - - - message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) should return int but returns float\\|int\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Drawing.php - - message: "#^Parameter \\#1 \\$fp of function fread expects resource, resource\\|false given\\.$#" count: 2 @@ -4240,11 +4235,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/Font.php - - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects int, float\\|int given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Font.php - - message: "#^Parameter \\#2 \\$pDefaultFont of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null given\\.$#" count: 1 @@ -4860,16 +4850,6 @@ parameters: count: 1 path: src/PhpSpreadsheet/Shared/XMLWriter.php - - - message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pointsToPixels\\(\\) expects int, float given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Xls.php - - - - message: "#^Parameter \\#1 \\$fontSizeInPoints of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:fontSizeToPixels\\(\\) expects int, float given\\.$#" - count: 1 - path: src/PhpSpreadsheet/Shared/Xls.php - - message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$workbookViewVisibilityValues has no typehint specified\\.$#" count: 1 diff --git a/src/PhpSpreadsheet/Helper/Dimension.php b/src/PhpSpreadsheet/Helper/Dimension.php new file mode 100644 index 00000000..136ffd7f --- /dev/null +++ b/src/PhpSpreadsheet/Helper/Dimension.php @@ -0,0 +1,103 @@ + 96.0 / 2.54, + self::UOM_MILLIMETERS => 96.0 / 25.4, + self::UOM_INCHES => 96.0, + self::UOM_PIXELS => 1.0, + self::UOM_POINTS => 96.0 / 72, + self::UOM_PICA => 96.0 * 12 / 72, + ]; + + /** + * Based on a standard column width of 8.54 units in MS Excel. + */ + const RELATIVE_UNITS = [ + 'em' => 10.0 / 8.54, + 'ex' => 10.0 / 8.54, + 'ch' => 10.0 / 8.54, + 'rem' => 10.0 / 8.54, + 'vw' => 8.54, + 'vh' => 8.54, + 'vmin' => 8.54, + 'vmax' => 8.54, + '%' => 8.54 / 100, + ]; + + /** + * @var float|int If this is a width, then size is measured in pixels (if is set) + * or in Excel's default column width units if $unit is null. + * If this is a height, then size is measured in pixels () + * or in points () if $unit is null. + */ + protected $size; + + /** + * @var null|string + */ + protected $unit; + + public function __construct(string $dimension) + { + [$size, $unit] = sscanf($dimension, '%[1234567890.]%s'); + $unit = strtolower(trim($unit)); + + // If a UoM is specified, then convert the size to pixels for internal storage + if (isset(self::ABSOLUTE_UNITS[$unit])) { + $size *= self::ABSOLUTE_UNITS[$unit]; + $this->unit = self::UOM_PIXELS; + } elseif (isset(self::RELATIVE_UNITS[$unit])) { + $size *= self::RELATIVE_UNITS[$unit]; + $size = round($size, 4); + } + + $this->size = $size; + } + + public function width(): float + { + return (float) ($this->unit === null) + ? $this->size + : round(Drawing::pixelsToCellDimension((int) $this->size, new Font(false)), 4); + } + + public function height(): float + { + return (float) ($this->unit === null) + ? $this->size + : $this->toUnit(self::UOM_POINTS); + } + + public function toUnit(string $unitOfMeasure): float + { + $unitOfMeasure = strtolower($unitOfMeasure); + if (!array_key_exists($unitOfMeasure, self::ABSOLUTE_UNITS)) { + throw new Exception("{$unitOfMeasure} is not a vaid unit of measure"); + } + + $size = $this->size; + if ($this->unit === null) { + $size = Drawing::cellDimensionToPixels($size, new Font(false)); + } + + return $size / self::ABSOLUTE_UNITS[$unitOfMeasure]; + } +} diff --git a/src/PhpSpreadsheet/Reader/Html.php b/src/PhpSpreadsheet/Reader/Html.php index ced65e97..fe2ea018 100644 --- a/src/PhpSpreadsheet/Reader/Html.php +++ b/src/PhpSpreadsheet/Reader/Html.php @@ -7,6 +7,7 @@ use DOMElement; use DOMNode; use DOMText; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Style\Border; @@ -527,14 +528,14 @@ class Html extends BaseReader private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void { if (isset($attributeArray['width'])) { - $sheet->getColumnDimension($column)->setWidth($attributeArray['width']); + $sheet->getColumnDimension($column)->setWidth((new CssDimension($attributeArray['width']))->width()); } } private function processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray): void { if (isset($attributeArray['height'])) { - $sheet->getRowDimension($row)->setRowHeight($attributeArray['height']); + $sheet->getRowDimension($row)->setRowHeight((new CssDimension($attributeArray['height']))->height()); } } @@ -878,14 +879,14 @@ class Html extends BaseReader case 'width': $sheet->getColumnDimension($column)->setWidth( - (float) str_replace(['px', 'pt'], '', $styleValue) + (new CssDimension($styleValue ?? ''))->width() ); break; case 'height': $sheet->getRowDimension($row)->setRowHeight( - (float) str_replace(['px', 'pt'], '', $styleValue) + (new CssDimension($styleValue ?? ''))->height() ); break; diff --git a/src/PhpSpreadsheet/Shared/Drawing.php b/src/PhpSpreadsheet/Shared/Drawing.php index ebb87ed1..08982d84 100644 --- a/src/PhpSpreadsheet/Shared/Drawing.php +++ b/src/PhpSpreadsheet/Shared/Drawing.php @@ -9,26 +9,26 @@ class Drawing /** * Convert pixels to EMU. * - * @param int $pValue Value in pixels + * @param int $pixelValue Value in pixels * * @return int Value in EMU */ - public static function pixelsToEMU($pValue) + public static function pixelsToEMU($pixelValue) { - return $pValue * 9525; + return $pixelValue * 9525; } /** * Convert EMU to pixels. * - * @param int $pValue Value in EMU + * @param int $emuValue Value in EMU * * @return int Value in pixels */ - public static function EMUToPixels($pValue) + public static function EMUToPixels($emuValue) { - if ($pValue != 0) { - return (int) round($pValue / 9525); + if ($emuValue != 0) { + return (int) round($emuValue / 9525); } return 0; @@ -39,12 +39,12 @@ class Drawing * By inspection of a real Excel file using Calibri 11, one finds 1000px ~ 142.85546875 * This gives a conversion factor of 7. Also, we assume that pixels and font size are proportional. * - * @param int $pValue Value in pixels + * @param int $pixelValue Value in pixels * @param \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont Default font of the workbook * - * @return int Value in cell dimension + * @return float|int Value in cell dimension */ - public static function pixelsToCellDimension($pValue, \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont) + public static function pixelsToCellDimension($pixelValue, \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont) { // Font name and size $name = $pDefaultFont->getName(); @@ -52,25 +52,25 @@ class Drawing if (isset(Font::$defaultColumnWidths[$name][$size])) { // Exact width can be determined - $colWidth = $pValue * Font::$defaultColumnWidths[$name][$size]['width'] / Font::$defaultColumnWidths[$name][$size]['px']; - } else { - // We don't have data for this particular font and size, use approximation by - // extrapolating from Calibri 11 - $colWidth = $pValue * 11 * Font::$defaultColumnWidths['Calibri'][11]['width'] / Font::$defaultColumnWidths['Calibri'][11]['px'] / $size; + return $pixelValue * Font::$defaultColumnWidths[$name][$size]['width'] + / Font::$defaultColumnWidths[$name][$size]['px']; } - return $colWidth; + // We don't have data for this particular font and size, use approximation by + // extrapolating from Calibri 11 + return $pixelValue * 11 * Font::$defaultColumnWidths['Calibri'][11]['width'] + / Font::$defaultColumnWidths['Calibri'][11]['px'] / $size; } /** * Convert column width from (intrinsic) Excel units to pixels. * - * @param float $pValue Value in cell dimension + * @param float $cellWidth Value in cell dimension * @param \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont Default font of the workbook * * @return int Value in pixels */ - public static function cellDimensionToPixels($pValue, \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont) + public static function cellDimensionToPixels($cellWidth, \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont) { // Font name and size $name = $pDefaultFont->getName(); @@ -78,11 +78,13 @@ class Drawing if (isset(Font::$defaultColumnWidths[$name][$size])) { // Exact width can be determined - $colWidth = $pValue * Font::$defaultColumnWidths[$name][$size]['px'] / Font::$defaultColumnWidths[$name][$size]['width']; + $colWidth = $cellWidth * Font::$defaultColumnWidths[$name][$size]['px'] + / Font::$defaultColumnWidths[$name][$size]['width']; } else { // We don't have data for this particular font and size, use approximation by // extrapolating from Calibri 11 - $colWidth = $pValue * $size * Font::$defaultColumnWidths['Calibri'][11]['px'] / Font::$defaultColumnWidths['Calibri'][11]['width'] / 11; + $colWidth = $cellWidth * $size * Font::$defaultColumnWidths['Calibri'][11]['px'] + / Font::$defaultColumnWidths['Calibri'][11]['width'] / 11; } // Round pixels to closest integer @@ -94,26 +96,26 @@ class Drawing /** * Convert pixels to points. * - * @param int $pValue Value in pixels + * @param int $pixelValue Value in pixels * * @return float Value in points */ - public static function pixelsToPoints($pValue) + public static function pixelsToPoints($pixelValue) { - return $pValue * 0.75; + return $pixelValue * 0.75; } /** * Convert points to pixels. * - * @param int $pValue Value in points + * @param int $pointValue Value in points * * @return int Value in pixels */ - public static function pointsToPixels($pValue) + public static function pointsToPixels($pointValue) { - if ($pValue != 0) { - return (int) ceil($pValue / 0.75); + if ($pointValue != 0) { + return (int) ceil($pointValue / 0.75); } return 0; diff --git a/src/PhpSpreadsheet/Shared/Font.php b/src/PhpSpreadsheet/Shared/Font.php index 00629e69..a0817448 100644 --- a/src/PhpSpreadsheet/Shared/Font.php +++ b/src/PhpSpreadsheet/Shared/Font.php @@ -265,7 +265,7 @@ class Font } // Convert from pixel width to column width - $columnWidth = Drawing::pixelsToCellDimension($columnWidth, $defaultFont); + $columnWidth = Drawing::pixelsToCellDimension((int) $columnWidth, $defaultFont); // Return return (int) round($columnWidth, 6); diff --git a/src/PhpSpreadsheet/Shared/Xls.php b/src/PhpSpreadsheet/Shared/Xls.php index 26035ec6..cd2482b0 100644 --- a/src/PhpSpreadsheet/Shared/Xls.php +++ b/src/PhpSpreadsheet/Shared/Xls.php @@ -3,6 +3,7 @@ namespace PhpOffice\PhpSpreadsheet\Shared; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; +use PhpOffice\PhpSpreadsheet\Helper\Dimension; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; class Xls @@ -76,12 +77,11 @@ class Xls } elseif ($sheet->getDefaultRowDimension()->getRowHeight() != -1) { // then we have a default row dimension with explicit height $defaultRowDimension = $sheet->getDefaultRowDimension(); - $rowHeight = $defaultRowDimension->getRowHeight(); - $pixelRowHeight = Drawing::pointsToPixels($rowHeight); + $pixelRowHeight = $defaultRowDimension->getRowHeight(Dimension::UOM_PIXELS); } else { // we don't even have any default row dimension. Height depends on default font $pointRowHeight = Font::getDefaultRowHeightByFont($font); - $pixelRowHeight = Font::fontSizeToPixels($pointRowHeight); + $pixelRowHeight = Font::fontSizeToPixels((int) $pointRowHeight); } // now find the effective row height in pixels @@ -91,7 +91,7 @@ class Xls $effectivePixelRowHeight = $pixelRowHeight; } - return $effectivePixelRowHeight; + return (int) $effectivePixelRowHeight; } /** diff --git a/src/PhpSpreadsheet/Worksheet/ColumnDimension.php b/src/PhpSpreadsheet/Worksheet/ColumnDimension.php index 12b1efdf..4ea30c8f 100644 --- a/src/PhpSpreadsheet/Worksheet/ColumnDimension.php +++ b/src/PhpSpreadsheet/Worksheet/ColumnDimension.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet; +use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension; + class ColumnDimension extends Dimension { /** @@ -63,20 +65,32 @@ class ColumnDimension extends Dimension /** * Get Width. + * + * Each unit of column width is equal to the width of one character in the default font size. + * By default, this will be the return value; but this method also accepts a unit of measure argument and will + * return the value converted to the specified UoM using an approximation method. */ - public function getWidth(): float + public function getWidth(?string $unitOfMeasure = null): float { - return $this->width; + return ($unitOfMeasure === null || $this->width < 0) + ? $this->width + : (new CssDimension((string) $this->width))->toUnit($unitOfMeasure); } /** * Set Width. * + * Each unit of column width is equal to the width of one character in the default font size. + * By default, this will be the unit of measure for the passed value; but this method accepts a unit of measure + * argument, and will convert the value from the specified UoM using an approximation method. + * * @return $this */ - public function setWidth(float $width) + public function setWidth(float $width, ?string $unitOfMeasure = null) { - $this->width = $width; + $this->width = ($unitOfMeasure === null || $width < 0) + ? $width + : (new CssDimension("{$width}{$unitOfMeasure}"))->width(); return $this; } diff --git a/src/PhpSpreadsheet/Worksheet/RowDimension.php b/src/PhpSpreadsheet/Worksheet/RowDimension.php index d86dd80f..006157b2 100644 --- a/src/PhpSpreadsheet/Worksheet/RowDimension.php +++ b/src/PhpSpreadsheet/Worksheet/RowDimension.php @@ -2,6 +2,8 @@ namespace PhpOffice\PhpSpreadsheet\Worksheet; +use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension; + class RowDimension extends Dimension { /** @@ -63,24 +65,32 @@ class RowDimension extends Dimension /** * Get Row Height. + * By default, this will be in points; but this method accepts a unit of measure + * argument, and will convert the value to the specified UoM. * * @return float */ - public function getRowHeight() + public function getRowHeight(?string $unitOfMeasure = null) { - return $this->height; + return ($unitOfMeasure === null || $this->height < 0) + ? $this->height + : (new CssDimension($this->height . CssDimension::UOM_POINTS))->toUnit($unitOfMeasure); } /** * Set Row Height. * - * @param float $height + * @param float $height in points + * By default, this will be the passed argument value; but this method accepts a unit of measure + * argument, and will convert the passed argument value to points from the specified UoM * * @return $this */ - public function setRowHeight($height) + public function setRowHeight($height, ?string $unitOfMeasure = null) { - $this->height = $height; + $this->height = ($unitOfMeasure === null || $height < 0) + ? $height + : (new CssDimension("{$height}{$unitOfMeasure}"))->height(); return $this; } diff --git a/tests/PhpSpreadsheetTests/Helper/DimensionTest.php b/tests/PhpSpreadsheetTests/Helper/DimensionTest.php new file mode 100644 index 00000000..87bce380 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Helper/DimensionTest.php @@ -0,0 +1,72 @@ +width(); + self::assertSame($expectedResult, $result); + } + + /** + * @dataProvider providerConvertUoM + */ + public function testConvertDimension(float $expectedResult, string $dimension, string $unitOfMeasure): void + { + $result = (new Dimension($dimension))->toUnit($unitOfMeasure); + self::assertSame($expectedResult, $result); + } + + public function testConvertDimensionInvalidUoM(): void + { + $this->expectException(Exception::class); + $this->expectExceptionMessage('pikachu is not a vaid unit of measure'); + (new Dimension('999'))->toUnit('pikachu'); + } + + public function providerCellWidth(): array + { + return [ + [12.0, '12'], + [2.2852, '12pt'], + [4.5703, '24 pt'], + [5.1416, '36px'], + [5.7129, '2.5pc'], + [13.7109, '2.54cm'], + [13.7109, '25.4mm'], + [13.7109, '1in'], + [4.27, '50%'], + [3.7471, '3.2em'], + [2.3419, '2ch'], + [4.6838, '4ex'], + [14.0515, '12rem'], + ]; + } + + public function providerConvertUoM(): array + { + return [ + [60, '8.54', Dimension::UOM_PIXELS], + [100, '100px', Dimension::UOM_PIXELS], + [150, '200px', Dimension::UOM_POINTS], + [45, '8.54', Dimension::UOM_POINTS], + [12.5, '200px', Dimension::UOM_PICA], + [3.75, '8.54', Dimension::UOM_PICA], + [3.125, '300px', Dimension::UOM_INCHES], + [0.625, '8.54', Dimension::UOM_INCHES], + [7.9375, '300px', Dimension::UOM_CENTIMETERS], + [1.5875, '8.54', Dimension::UOM_CENTIMETERS], + [79.375, '300px', Dimension::UOM_MILLIMETERS], + [15.875, '8.54', Dimension::UOM_MILLIMETERS], + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php b/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php index 7acc5527..38a9bc9e 100644 --- a/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php +++ b/tests/PhpSpreadsheetTests/Reader/Html/HtmlTest.php @@ -136,6 +136,7 @@ class HtmlTest extends TestCase 50px 100px + 50px '; $filename = HtmlHelper::createHtml($html); @@ -143,10 +144,16 @@ class HtmlTest extends TestCase $firstSheet = $spreadsheet->getSheet(0); $dimension = $firstSheet->getColumnDimension('A'); + self::assertNotNull($dimension); self::assertEquals(50, $dimension->getWidth()); $dimension = $firstSheet->getColumnDimension('B'); - self::assertEquals(100, $dimension->getWidth()); + self::assertNotNull($dimension); + self::assertEquals(100, $dimension->getWidth('px')); + + $dimension = $firstSheet->getColumnDimension('C'); + self::assertNotNull($dimension); + self::assertEquals(50, $dimension->getWidth('px')); } public function testCanApplyInlineHeight(): void @@ -158,16 +165,25 @@ class HtmlTest extends TestCase 2 + + 1 + '; $filename = HtmlHelper::createHtml($html); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true); $firstSheet = $spreadsheet->getSheet(0); $dimension = $firstSheet->getRowDimension(1); + self::assertNotNull($dimension); self::assertEquals(50, $dimension->getRowHeight()); $dimension = $firstSheet->getRowDimension(2); - self::assertEquals(100, $dimension->getRowHeight()); + self::assertNotNull($dimension); + self::assertEquals(100, $dimension->getRowHeight('px')); + + $dimension = $firstSheet->getRowDimension(3); + self::assertNotNull($dimension); + self::assertEquals(50, $dimension->getRowHeight('px')); } public function testCanApplyAlignment(): void diff --git a/tests/PhpSpreadsheetTests/Shared/DrawingTest.php b/tests/PhpSpreadsheetTests/Shared/DrawingTest.php new file mode 100644 index 00000000..dc0ff631 --- /dev/null +++ b/tests/PhpSpreadsheetTests/Shared/DrawingTest.php @@ -0,0 +1,80 @@ +setName($fontName); + $font->setSize($fontSize); + + $result = Drawing::pixelsToCellDimension($pixelSize, $font); + self::assertSame($expectedResult, $result); + } + + /** + * @dataProvider providerCellDimensionToPixels + */ + public function testCellDimensionToPixels( + int $expectedResult, + int $cellSize, + string $fontName, + int $fontSize + ): void { + $font = new Font(); + $font->setName($fontName); + $font->setSize($fontSize); + + $result = Drawing::cellDimensionToPixels($cellSize, $font); + self::assertSame($expectedResult, $result); + } + + public function providerPixelsToCellDimension(): array + { + return [ + [19.9951171875, 100, 'Arial', 7], + [14.2822265625, 100, 'Arial', 9], + [14.2822265625, 100, 'Arial', 11], + [13.092041015625, 100, 'Arial', 12], // approximation by extrapolating from Calibri 11 + [19.9951171875, 100, 'Calibri', 7], + [16.664341517857142, 100, 'Calibri', 9], + [14.2822265625, 100, 'Calibri', 11], + [13.092041015625, 100, 'Calibri', 12], // approximation by extrapolating from Calibri 11 + [19.9951171875, 100, 'Verdana', 7], + [12.5, 100, 'Verdana', 9], + [13.092041015625, 100, 'Verdana', 12], // approximation by extrapolating from Calibri 11 + [17.4560546875, 100, 'Wingdings', 9], // approximation by extrapolating from Calibri 11 + ]; + } + + public function providerCellDimensionToPixels(): array + { + return [ + [500, 100, 'Arial', 7], + [700, 100, 'Arial', 9], + [700, 100, 'Arial', 11], + [764, 100, 'Arial', 12], // approximation by extrapolating from Calibri 11 + [500, 100, 'Calibri', 7], + [600, 100, 'Calibri', 9], + [700, 100, 'Calibri', 11], + [764, 100, 'Calibri', 12], // approximation by extrapolating from Calibri 11 + [500, 100, 'Verdana', 7], + [800, 100, 'Verdana', 9], + [764, 100, 'Verdana', 12], // approximation by extrapolating from Calibri 11 + [573, 100, 'Wingdings', 9], // approximation by extrapolating from Calibri 11 + ]; + } +} diff --git a/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php b/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php index 8062a24c..1994fa81 100644 --- a/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php +++ b/tests/PhpSpreadsheetTests/Worksheet/ColumnDimensionTest.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheetTests\Worksheet; +use PhpOffice\PhpSpreadsheet\Helper\Dimension; use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension; use PHPUnit\Framework\TestCase; @@ -29,9 +30,18 @@ class ColumnDimensionTest extends TestCase { $expected = 1.2; $columnDimension = new ColumnDimension(); + $columnDimension->setWidth($expected); $result = $columnDimension->getWidth(); self::assertSame($expected, $result); + + $expectedPx = 32.0; + $expectedPt = 24.0; + $columnDimension->setWidth($expectedPx, Dimension::UOM_PIXELS); + $resultPx = $columnDimension->getWidth(Dimension::UOM_PIXELS); + self::assertSame($expectedPx, $resultPx); + $resultPt = $columnDimension->getWidth(Dimension::UOM_POINTS); + self::assertSame($expectedPt, $resultPt); } public function testGetAndSetAutoSize(): void diff --git a/tests/PhpSpreadsheetTests/Worksheet/RowDimensionTest.php b/tests/PhpSpreadsheetTests/Worksheet/RowDimensionTest.php new file mode 100644 index 00000000..a5b5a04d --- /dev/null +++ b/tests/PhpSpreadsheetTests/Worksheet/RowDimensionTest.php @@ -0,0 +1,55 @@ +getRowIndex(); + self::assertEquals($expected, $result); + } + + public function testGetAndSetColumnIndex(): void + { + $expected = 2; + $rowDimension = new RowDimension(); + $rowDimension->setRowIndex($expected); + $result = $rowDimension->getRowIndex(); + self::assertSame($expected, $result); + } + + public function testGetAndSetHeight(): void + { + $expected = 1.2; + $columnDimension = new RowDimension(); + + $columnDimension->setRowHeight($expected); + $result = $columnDimension->getRowHeight(); + self::assertSame($expected, $result); + + $expectedPx = 32.0; + $expectedPt = 24.0; + $columnDimension->setRowHeight($expectedPx, Dimension::UOM_PIXELS); + $resultPx = $columnDimension->getRowHeight(Dimension::UOM_PIXELS); + self::assertSame($expectedPx, $resultPx); + $resultPt = $columnDimension->getRowHeight(Dimension::UOM_POINTS); + self::assertSame($expectedPt, $resultPt); + } + + public function testRowZeroHeight(): void + { + $expected = true; + $rowDimension = new RowDimension(); + $rowDimension->setZeroHeight($expected); + $result = $rowDimension->getZeroHeight(); + self::assertTrue($result); + } +}