Skip to content

Commit 05466e9

Browse files
author
Mark Baker
authored
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
1 parent a911e9b commit 05466e9

File tree

15 files changed

+464
-69
lines changed

15 files changed

+464
-69
lines changed

CHANGELOG.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
1212
- 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)
1313
- See [documentation](https://phpspreadsheet.readthedocs.io/en/latest/topics/reading-and-writing-to-file/) for details
1414
- More flexibility in the StringValueBinder to determine what datatypes should be treated as strings [PR #2138](https://github.com/PHPOffice/PhpSpreadsheet/pull/2138)
15+
- 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)
16+
- 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)
1517

1618
### Changed
1719

@@ -27,7 +29,8 @@ and this project adheres to [Semantic Versioning](https://semver.org).
2729

2830
### Fixed
2931

30-
- Nothing.
32+
- 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).
33+
3134

3235
## 1.18.0 - 2021-05-31
3336

docs/topics/recipes.md

+49
Original file line numberDiff line numberDiff line change
@@ -1122,6 +1122,16 @@ A column's width can be set using the following code:
11221122
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(12);
11231123
```
11241124

1125+
If you want to set a column width using a different unit of measure,
1126+
then you can do so by telling PhpSpreadsheet what UoM the width value
1127+
that you are setting is measured in.
1128+
Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches),
1129+
`cm` (centimeters) and `mm` (millimeters).
1130+
1131+
```php
1132+
$spreadsheet->getActiveSheet()->getColumnDimension('D')->setWidth(120, 'pt');
1133+
```
1134+
11251135
If you want PhpSpreadsheet to perform an automatic width calculation,
11261136
use the following code. PhpSpreadsheet will approximate the column with
11271137
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
12071217
about 0.35mm). The default value is 12.75 pts; and the permitted range
12081218
of values is between 0 and 409 pts, where 0 pts is a hidden row.
12091219

1220+
If you want to set a row height using a different unit of measure,
1221+
then you can do so by telling PhpSpreadsheet what UoM the height value
1222+
that you are setting is measured in.
1223+
Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches),
1224+
`cm` (centimeters) and `mm` (millimeters).
1225+
1226+
```php
1227+
$spreadsheet->getActiveSheet()->getRowDimension('10')->setRowHeight(100, 'pt');
1228+
```
1229+
12101230
## Show/hide a row
12111231

12121232
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:
15601580
$spreadsheet->getActiveSheet()->getDefaultColumnDimension()->setWidth(12);
15611581
```
15621582

1583+
Excel measures column width in its own proprietary units, based on the number
1584+
of characters that will be displayed in the default font.
1585+
1586+
If you want to set the default column width using a different unit of measure,
1587+
then you can do so by telling PhpSpreadsheet what UoM the width value
1588+
that you are setting is measured in.
1589+
Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches),
1590+
`cm` (centimeters) and `mm` (millimeters).
1591+
1592+
```php
1593+
$spreadsheet->getActiveSheet()->getDefaultColumnDimension()->setWidth(400, 'pt');
1594+
```
1595+
and PhpSpreadsheet will handle the internal conversion.
1596+
15631597
## Setting the default row height
15641598

15651599
Default row height can be set using the following code:
@@ -1568,6 +1602,21 @@ Default row height can be set using the following code:
15681602
$spreadsheet->getActiveSheet()->getDefaultRowDimension()->setRowHeight(15);
15691603
```
15701604

1605+
Excel measures row height in points, where 1 pt is 1/72 of an inch (or
1606+
about 0.35mm). The default value is 12.75 pts; and the permitted range
1607+
of values is between 0 and 409 pts, where 0 pts is a hidden row.
1608+
1609+
If you want to set a row height using a different unit of measure,
1610+
then you can do so by telling PhpSpreadsheet what UoM the height value
1611+
that you are setting is measured in.
1612+
Valid units are `pt` (points), `px` (pixels), `pc` (pica), `in` (inches),
1613+
`cm` (centimeters) and `mm` (millimeters).
1614+
1615+
```php
1616+
$spreadsheet->getActiveSheet()->getDefaultRowDimension()->setRowHeight(100, 'pt');
1617+
```
1618+
1619+
15711620
## Add a GD drawing to a worksheet
15721621

15731622
There might be a situation where you want to generate an in-memory image

phpstan-baseline.neon

+1-21
Original file line numberDiff line numberDiff line change
@@ -2487,7 +2487,7 @@ parameters:
24872487

24882488
-
24892489
message: "#^Parameter \\#3 \\$subject of function str_replace expects array\\|string, string\\|null given\\.$#"
2490-
count: 4
2490+
count: 2
24912491
path: src/PhpSpreadsheet/Reader/Html.php
24922492

24932493
-
@@ -4100,11 +4100,6 @@ parameters:
41004100
count: 1
41014101
path: src/PhpSpreadsheet/Shared/Date.php
41024102

4103-
-
4104-
message: "#^Method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) should return int but returns float\\|int\\.$#"
4105-
count: 1
4106-
path: src/PhpSpreadsheet/Shared/Drawing.php
4107-
41084103
-
41094104
message: "#^Parameter \\#1 \\$fp of function fread expects resource, resource\\|false given\\.$#"
41104105
count: 2
@@ -4240,11 +4235,6 @@ parameters:
42404235
count: 1
42414236
path: src/PhpSpreadsheet/Shared/Font.php
42424237

4243-
-
4244-
message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects int, float\\|int given\\.$#"
4245-
count: 1
4246-
path: src/PhpSpreadsheet/Shared/Font.php
4247-
42484238
-
42494239
message: "#^Parameter \\#2 \\$pDefaultFont of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pixelsToCellDimension\\(\\) expects PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font, PhpOffice\\\\PhpSpreadsheet\\\\Style\\\\Font\\|null given\\.$#"
42504240
count: 1
@@ -4860,16 +4850,6 @@ parameters:
48604850
count: 1
48614851
path: src/PhpSpreadsheet/Shared/XMLWriter.php
48624852

4863-
-
4864-
message: "#^Parameter \\#1 \\$pValue of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Drawing\\:\\:pointsToPixels\\(\\) expects int, float given\\.$#"
4865-
count: 1
4866-
path: src/PhpSpreadsheet/Shared/Xls.php
4867-
4868-
-
4869-
message: "#^Parameter \\#1 \\$fontSizeInPoints of static method PhpOffice\\\\PhpSpreadsheet\\\\Shared\\\\Font\\:\\:fontSizeToPixels\\(\\) expects int, float given\\.$#"
4870-
count: 1
4871-
path: src/PhpSpreadsheet/Shared/Xls.php
4872-
48734853
-
48744854
message: "#^Property PhpOffice\\\\PhpSpreadsheet\\\\Spreadsheet\\:\\:\\$workbookViewVisibilityValues has no typehint specified\\.$#"
48754855
count: 1
+103
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
namespace PhpOffice\PhpSpreadsheet\Helper;
4+
5+
use PhpOffice\PhpSpreadsheet\Exception;
6+
use PhpOffice\PhpSpreadsheet\Shared\Drawing;
7+
use PhpOffice\PhpSpreadsheet\Style\Font;
8+
9+
class Dimension
10+
{
11+
public const UOM_CENTIMETERS = 'cm';
12+
public const UOM_MILLIMETERS = 'mm';
13+
public const UOM_INCHES = 'in';
14+
public const UOM_PIXELS = 'px';
15+
public const UOM_POINTS = 'pt';
16+
public const UOM_PICA = 'pc';
17+
18+
/**
19+
* Based on 96 dpi.
20+
*/
21+
const ABSOLUTE_UNITS = [
22+
self::UOM_CENTIMETERS => 96.0 / 2.54,
23+
self::UOM_MILLIMETERS => 96.0 / 25.4,
24+
self::UOM_INCHES => 96.0,
25+
self::UOM_PIXELS => 1.0,
26+
self::UOM_POINTS => 96.0 / 72,
27+
self::UOM_PICA => 96.0 * 12 / 72,
28+
];
29+
30+
/**
31+
* Based on a standard column width of 8.54 units in MS Excel.
32+
*/
33+
const RELATIVE_UNITS = [
34+
'em' => 10.0 / 8.54,
35+
'ex' => 10.0 / 8.54,
36+
'ch' => 10.0 / 8.54,
37+
'rem' => 10.0 / 8.54,
38+
'vw' => 8.54,
39+
'vh' => 8.54,
40+
'vmin' => 8.54,
41+
'vmax' => 8.54,
42+
'%' => 8.54 / 100,
43+
];
44+
45+
/**
46+
* @var float|int If this is a width, then size is measured in pixels (if is set)
47+
* or in Excel's default column width units if $unit is null.
48+
* If this is a height, then size is measured in pixels ()
49+
* or in points () if $unit is null.
50+
*/
51+
protected $size;
52+
53+
/**
54+
* @var null|string
55+
*/
56+
protected $unit;
57+
58+
public function __construct(string $dimension)
59+
{
60+
[$size, $unit] = sscanf($dimension, '%[1234567890.]%s');
61+
$unit = strtolower(trim($unit));
62+
63+
// If a UoM is specified, then convert the size to pixels for internal storage
64+
if (isset(self::ABSOLUTE_UNITS[$unit])) {
65+
$size *= self::ABSOLUTE_UNITS[$unit];
66+
$this->unit = self::UOM_PIXELS;
67+
} elseif (isset(self::RELATIVE_UNITS[$unit])) {
68+
$size *= self::RELATIVE_UNITS[$unit];
69+
$size = round($size, 4);
70+
}
71+
72+
$this->size = $size;
73+
}
74+
75+
public function width(): float
76+
{
77+
return (float) ($this->unit === null)
78+
? $this->size
79+
: round(Drawing::pixelsToCellDimension((int) $this->size, new Font(false)), 4);
80+
}
81+
82+
public function height(): float
83+
{
84+
return (float) ($this->unit === null)
85+
? $this->size
86+
: $this->toUnit(self::UOM_POINTS);
87+
}
88+
89+
public function toUnit(string $unitOfMeasure): float
90+
{
91+
$unitOfMeasure = strtolower($unitOfMeasure);
92+
if (!array_key_exists($unitOfMeasure, self::ABSOLUTE_UNITS)) {
93+
throw new Exception("{$unitOfMeasure} is not a vaid unit of measure");
94+
}
95+
96+
$size = $this->size;
97+
if ($this->unit === null) {
98+
$size = Drawing::cellDimensionToPixels($size, new Font(false));
99+
}
100+
101+
return $size / self::ABSOLUTE_UNITS[$unitOfMeasure];
102+
}
103+
}

src/PhpSpreadsheet/Reader/Html.php

+5-4
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use DOMNode;
88
use DOMText;
99
use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
10+
use PhpOffice\PhpSpreadsheet\Helper\Dimension as CssDimension;
1011
use PhpOffice\PhpSpreadsheet\Reader\Security\XmlScanner;
1112
use PhpOffice\PhpSpreadsheet\Spreadsheet;
1213
use PhpOffice\PhpSpreadsheet\Style\Border;
@@ -527,14 +528,14 @@ private function processDomElementBgcolor(Worksheet $sheet, int $row, string $co
527528
private function processDomElementWidth(Worksheet $sheet, string $column, array $attributeArray): void
528529
{
529530
if (isset($attributeArray['width'])) {
530-
$sheet->getColumnDimension($column)->setWidth($attributeArray['width']);
531+
$sheet->getColumnDimension($column)->setWidth((new CssDimension($attributeArray['width']))->width());
531532
}
532533
}
533534

534535
private function processDomElementHeight(Worksheet $sheet, int $row, array $attributeArray): void
535536
{
536537
if (isset($attributeArray['height'])) {
537-
$sheet->getRowDimension($row)->setRowHeight($attributeArray['height']);
538+
$sheet->getRowDimension($row)->setRowHeight((new CssDimension($attributeArray['height']))->height());
538539
}
539540
}
540541

@@ -878,14 +879,14 @@ private function applyInlineStyle(&$sheet, $row, $column, $attributeArray): void
878879

879880
case 'width':
880881
$sheet->getColumnDimension($column)->setWidth(
881-
(float) str_replace(['px', 'pt'], '', $styleValue)
882+
(new CssDimension($styleValue ?? ''))->width()
882883
);
883884

884885
break;
885886

886887
case 'height':
887888
$sheet->getRowDimension($row)->setRowHeight(
888-
(float) str_replace(['px', 'pt'], '', $styleValue)
889+
(new CssDimension($styleValue ?? ''))->height()
889890
);
890891

891892
break;

0 commit comments

Comments
 (0)