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
This commit is contained in:
Mark Baker 2021-06-11 17:29:49 +02:00 committed by GitHub
parent a911e9bb7b
commit 05466e99ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 464 additions and 69 deletions

View File

@ -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) - 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 - 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) - 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 ### Changed
@ -27,7 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
### Fixed ### 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 ## 1.18.0 - 2021-05-31

View File

@ -1122,6 +1122,16 @@ A column's width can be set using the following code:
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(12); $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, If you want PhpSpreadsheet to perform an automatic width calculation,
use the following code. PhpSpreadsheet will approximate the column with use the following code. PhpSpreadsheet will approximate the column with
to the width of the widest column value. 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 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. 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 ## Show/hide a row
To set a worksheet''s row visibility, you can use the following code. 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); $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 ## Setting the default row height
Default row height can be set using the following code: 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); $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 ## Add a GD drawing to a worksheet
There might be a situation where you want to generate an in-memory image There might be a situation where you want to generate an in-memory image

View File

@ -2487,7 +2487,7 @@ parameters:
- -
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#" message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
count: 4 count: 2
path: src/PhpSpreadsheet/Reader/Html.php path: src/PhpSpreadsheet/Reader/Html.php
- -
@ -4100,11 +4100,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/Date.php 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\\.$#" message: "#^Parameter \\#1 \\$fp of function fread expects resource, resource\\|false given\\.$#"
count: 2 count: 2
@ -4240,11 +4235,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/Font.php 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\\.$#" 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 count: 1
@ -4860,16 +4850,6 @@ parameters:
count: 1 count: 1
path: src/PhpSpreadsheet/Shared/XMLWriter.php 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\\.$#" message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$workbookViewVisibilityValues has no typehint specified\\.$#"
count: 1 count: 1

View File

@ -0,0 +1,103 @@
<?php
namespace PhpOffice\PhpSpreadsheet\Helper;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Shared\Drawing;
use PhpOffice\PhpSpreadsheet\Style\Font;
class Dimension
{
public const UOM_CENTIMETERS = 'cm';
public const UOM_MILLIMETERS = 'mm';
public const UOM_INCHES = 'in';
public const UOM_PIXELS = 'px';
public const UOM_POINTS = 'pt';
public const UOM_PICA = 'pc';
/**
* Based on 96 dpi.
*/
const ABSOLUTE_UNITS = [
self::UOM_CENTIMETERS => 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];
}
}

View File

@ -7,6 +7,7 @@ use DOMElement;
use DOMNode; use DOMNode;
use DOMText; use DOMText;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner; use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
use PhpOffice\PhpSpreadsheet\Spreadsheet; use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Style\Border; use PhpOffice\PhpSpreadsheet\Style\Border;
@ -527,14 +528,14 @@ class Html extends BaseReader
private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void
{ {
if (isset($attributeArray['width'])) { 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 private function processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray): void
{ {
if (isset($attributeArray['height'])) { 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': case 'width':
$sheet->getColumnDimension($column)->setWidth( $sheet->getColumnDimension($column)->setWidth(
(float) str_replace(['px', 'pt'], '', $styleValue) (new CssDimension($styleValue ?? ''))->width()
); );
break; break;
case 'height': case 'height':
$sheet->getRowDimension($row)->setRowHeight( $sheet->getRowDimension($row)->setRowHeight(
(float) str_replace(['px', 'pt'], '', $styleValue) (new CssDimension($styleValue ?? ''))->height()
); );
break; break;

View File

@ -9,26 +9,26 @@ class Drawing
/** /**
* Convert pixels to EMU. * Convert pixels to EMU.
* *
* @param int $pValue Value in pixels * @param int $pixelValue Value in pixels
* *
* @return int Value in EMU * @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. * Convert EMU to pixels.
* *
* @param int $pValue Value in EMU * @param int $emuValue Value in EMU
* *
* @return int Value in pixels * @return int Value in pixels
*/ */
public static function EMUToPixels($pValue) public static function EMUToPixels($emuValue)
{ {
if ($pValue != 0) { if ($emuValue != 0) {
return (int) round($pValue / 9525); return (int) round($emuValue / 9525);
} }
return 0; return 0;
@ -39,12 +39,12 @@ class Drawing
* By inspection of a real Excel file using Calibri 11, one finds 1000px ~ 142.85546875 * 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. * 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 * @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 // Font name and size
$name = $pDefaultFont->getName(); $name = $pDefaultFont->getName();
@ -52,25 +52,25 @@ class Drawing
if (isset(Font::$defaultColumnWidths[$name][$size])) { if (isset(Font::$defaultColumnWidths[$name][$size])) {
// Exact width can be determined // Exact width can be determined
$colWidth = $pValue * Font::$defaultColumnWidths[$name][$size]['width'] / Font::$defaultColumnWidths[$name][$size]['px']; return $pixelValue * Font::$defaultColumnWidths[$name][$size]['width']
} else { / Font::$defaultColumnWidths[$name][$size]['px'];
// 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 $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. * 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 * @param \PhpOffice\PhpSpreadsheet\Style\Font $pDefaultFont Default font of the workbook
* *
* @return int Value in pixels * @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 // Font name and size
$name = $pDefaultFont->getName(); $name = $pDefaultFont->getName();
@ -78,11 +78,13 @@ class Drawing
if (isset(Font::$defaultColumnWidths[$name][$size])) { if (isset(Font::$defaultColumnWidths[$name][$size])) {
// Exact width can be determined // 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 { } else {
// We don't have data for this particular font and size, use approximation by // We don't have data for this particular font and size, use approximation by
// extrapolating from Calibri 11 // 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 // Round pixels to closest integer
@ -94,26 +96,26 @@ class Drawing
/** /**
* Convert pixels to points. * Convert pixels to points.
* *
* @param int $pValue Value in pixels * @param int $pixelValue Value in pixels
* *
* @return float Value in points * @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. * Convert points to pixels.
* *
* @param int $pValue Value in points * @param int $pointValue Value in points
* *
* @return int Value in pixels * @return int Value in pixels
*/ */
public static function pointsToPixels($pValue) public static function pointsToPixels($pointValue)
{ {
if ($pValue != 0) { if ($pointValue != 0) {
return (int) ceil($pValue / 0.75); return (int) ceil($pointValue / 0.75);
} }
return 0; return 0;

View File

@ -265,7 +265,7 @@ class Font
} }
// Convert from pixel width to column width // Convert from pixel width to column width
$columnWidth = Drawing::pixelsToCellDimension($columnWidth, $defaultFont); $columnWidth = Drawing::pixelsToCellDimension((int) $columnWidth, $defaultFont);
// Return // Return
return (int) round($columnWidth, 6); return (int) round($columnWidth, 6);

View File

@ -3,6 +3,7 @@
namespace PhpOffice\PhpSpreadsheet\Shared; namespace PhpOffice\PhpSpreadsheet\Shared;
use PhpOffice\PhpSpreadsheet\Cell\Coordinate; use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
use PhpOffice\PhpSpreadsheet\Helper\Dimension;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet; use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
class Xls class Xls
@ -76,12 +77,11 @@ class Xls
} elseif ($sheet->getDefaultRowDimension()->getRowHeight() != -1) { } elseif ($sheet->getDefaultRowDimension()->getRowHeight() != -1) {
// then we have a default row dimension with explicit height // then we have a default row dimension with explicit height
$defaultRowDimension = $sheet->getDefaultRowDimension(); $defaultRowDimension = $sheet->getDefaultRowDimension();
$rowHeight = $defaultRowDimension->getRowHeight(); $pixelRowHeight = $defaultRowDimension->getRowHeight(Dimension::UOM_PIXELS);
$pixelRowHeight = Drawing::pointsToPixels($rowHeight);
} else { } else {
// we don't even have any default row dimension. Height depends on default font // we don't even have any default row dimension. Height depends on default font
$pointRowHeight = Font::getDefaultRowHeightByFont($font); $pointRowHeight = Font::getDefaultRowHeightByFont($font);
$pixelRowHeight = Font::fontSizeToPixels($pointRowHeight); $pixelRowHeight = Font::fontSizeToPixels((int) $pointRowHeight);
} }
// now find the effective row height in pixels // now find the effective row height in pixels
@ -91,7 +91,7 @@ class Xls
$effectivePixelRowHeight = $pixelRowHeight; $effectivePixelRowHeight = $pixelRowHeight;
} }
return $effectivePixelRowHeight; return (int) $effectivePixelRowHeight;
} }
/** /**

View File

@ -2,6 +2,8 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet; namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
class ColumnDimension extends Dimension class ColumnDimension extends Dimension
{ {
/** /**
@ -63,20 +65,32 @@ class ColumnDimension extends Dimension
/** /**
* Get Width. * 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. * 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 * @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; return $this;
} }

View File

@ -2,6 +2,8 @@
namespace PhpOffice\PhpSpreadsheet\Worksheet; namespace PhpOffice\PhpSpreadsheet\Worksheet;
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
class RowDimension extends Dimension class RowDimension extends Dimension
{ {
/** /**
@ -63,24 +65,32 @@ class RowDimension extends Dimension
/** /**
* Get Row Height. * 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 * @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. * 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 * @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; return $this;
} }

View File

@ -0,0 +1,72 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Helper;
use PhpOffice\PhpSpreadsheet\Exception;
use PhpOffice\PhpSpreadsheet\Helper\Dimension;
use PHPUnit\Framework\TestCase;
class DimensionTest extends TestCase
{
/**
* @dataProvider providerCellWidth
*/
public function testCreateDimension(float $expectedResult, string $dimension): void
{
$result = (new Dimension($dimension))->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],
];
}
}

View File

@ -136,6 +136,7 @@ class HtmlTest extends TestCase
<tr> <tr>
<td width="50">50px</td> <td width="50">50px</td>
<td style="width: 100px;">100px</td> <td style="width: 100px;">100px</td>
<td width="50px">50px</td>
</tr> </tr>
</table>'; </table>';
$filename = HtmlHelper::createHtml($html); $filename = HtmlHelper::createHtml($html);
@ -143,10 +144,16 @@ class HtmlTest extends TestCase
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$dimension = $firstSheet->getColumnDimension('A'); $dimension = $firstSheet->getColumnDimension('A');
self::assertNotNull($dimension);
self::assertEquals(50, $dimension->getWidth()); self::assertEquals(50, $dimension->getWidth());
$dimension = $firstSheet->getColumnDimension('B'); $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 public function testCanApplyInlineHeight(): void
@ -158,16 +165,25 @@ class HtmlTest extends TestCase
<tr> <tr>
<td style="height: 100px;">2</td> <td style="height: 100px;">2</td>
</tr> </tr>
<tr>
<td height="50px">1</td>
</tr>
</table>'; </table>';
$filename = HtmlHelper::createHtml($html); $filename = HtmlHelper::createHtml($html);
$spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true); $spreadsheet = HtmlHelper::loadHtmlIntoSpreadsheet($filename, true);
$firstSheet = $spreadsheet->getSheet(0); $firstSheet = $spreadsheet->getSheet(0);
$dimension = $firstSheet->getRowDimension(1); $dimension = $firstSheet->getRowDimension(1);
self::assertNotNull($dimension);
self::assertEquals(50, $dimension->getRowHeight()); self::assertEquals(50, $dimension->getRowHeight());
$dimension = $firstSheet->getRowDimension(2); $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 public function testCanApplyAlignment(): void

View File

@ -0,0 +1,80 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Shared;
use PhpOffice\PhpSpreadsheet\Shared\Drawing;
use PhpOffice\PhpSpreadsheet\Style\Font;
use PHPUnit\Framework\TestCase;
class DrawingTest extends TestCase
{
/**
* @dataProvider providerPixelsToCellDimension
*/
public function testPixelsToCellDimension(
float $expectedResult,
int $pixelSize,
string $fontName,
int $fontSize
): void {
$font = new Font();
$font->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
];
}
}

View File

@ -2,6 +2,7 @@
namespace PhpOffice\PhpSpreadsheetTests\Worksheet; namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
use PhpOffice\PhpSpreadsheet\Helper\Dimension;
use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension; use PhpOffice\PhpSpreadsheet\Worksheet\ColumnDimension;
use PHPUnit\Framework\TestCase; use PHPUnit\Framework\TestCase;
@ -29,9 +30,18 @@ class ColumnDimensionTest extends TestCase
{ {
$expected = 1.2; $expected = 1.2;
$columnDimension = new ColumnDimension(); $columnDimension = new ColumnDimension();
$columnDimension->setWidth($expected); $columnDimension->setWidth($expected);
$result = $columnDimension->getWidth(); $result = $columnDimension->getWidth();
self::assertSame($expected, $result); 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 public function testGetAndSetAutoSize(): void

View File

@ -0,0 +1,55 @@
<?php
namespace PhpOffice\PhpSpreadsheetTests\Worksheet;
use PhpOffice\PhpSpreadsheet\Helper\Dimension;
use PhpOffice\PhpSpreadsheet\Worksheet\RowDimension;
use PHPUnit\Framework\TestCase;
class RowDimensionTest extends TestCase
{
public function testInstantiateColumnDimensionDefault(): void
{
$expected = 0;
$rowDimension = new RowDimension();
self::assertInstanceOf(RowDimension::class, $rowDimension);
$result = $rowDimension->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);
}
}