Skip to content

Commit

Permalink
Reader HTML: Support for differents size units for table (PHPOffice#2725
Browse files Browse the repository at this point in the history
)
  • Loading branch information
Progi1984 authored Jan 14, 2025
1 parent 639f396 commit f9da10e
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 42 deletions.
1 change: 1 addition & 0 deletions docs/changes/1.x/1.4.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@

- Writer ODText: Support for images inside a textRun by [@Progi1984](https://github.com/Progi1984) fixing [#2240](https://github.com/PHPOffice/PHPWord/issues/2240) in [#2668](https://github.com/PHPOffice/PHPWord/pull/2668)
- Allow vAlign and vMerge on Style\Cell to be set to null by [@SpraxDev](https://github.com/SpraxDev) fixing [#2673](https://github.com/PHPOffice/PHPWord/issues/2673) in [#2676](https://github.com/PHPOffice/PHPWord/pull/2676)
- Reader HTML: Support for differents size units for table by [@Progi1984](https://github.com/Progi1984) fixing [#2384](https://github.com/PHPOffice/PHPWord/issues/2384), [#2701](https://github.com/PHPOffice/PHPWord/issues/2701) in [#2725](https://github.com/PHPOffice/PHPWord/pull/2725)

### Miscellaneous

Expand Down
52 changes: 23 additions & 29 deletions src/PhpWord/Shared/Html.php
Original file line number Diff line number Diff line change
Expand Up @@ -128,21 +128,21 @@ protected static function parseInlineStyle($node, $styles = [])
break;
case 'width':
// tables, cells
$val = $val === 'auto' ? '100%' : $val;
if (false !== strpos($val, '%')) {
// e.g. <table width="100%"> or <td width="50%">
$styles['width'] = (int) $val * 50;
$styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::PERCENT;
} else {
// e.g. <table width="250> where "250" = 250px (always pixels)
$styles['width'] = Converter::pixelToTwip($val);
$styles['width'] = Converter::pixelToTwip(self::convertHtmlSize($val));
$styles['unit'] = \PhpOffice\PhpWord\SimpleType\TblWidth::TWIP;
}

break;
case 'cellspacing':
// tables e.g. <table cellspacing="2">, where "2" = 2px (always pixels)
$val = (int) $val . 'px';
$styles['cellSpacing'] = Converter::cssToTwip($val);
$styles['cellSpacing'] = Converter::pixelToTwip(self::convertHtmlSize($val));

break;
case 'bgcolor':
Expand Down Expand Up @@ -902,36 +902,12 @@ protected static function parseImage($node, $element)

break;
case 'width':
$width = $attribute->value;

// pt
if (false !== strpos($width, 'pt')) {
$width = Converter::pointToPixel((float) str_replace('pt', '', $width));
}

// px
if (false !== strpos($width, 'px')) {
$width = str_replace('px', '', $width);
}

$style['width'] = $width;
$style['width'] = self::convertHtmlSize($attribute->value);
$style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX;

break;
case 'height':
$height = $attribute->value;

// pt
if (false !== strpos($height, 'pt')) {
$height = Converter::pointToPixel((float) str_replace('pt', '', $height));
}

// px
if (false !== strpos($height, 'px')) {
$height = str_replace('px', '', $height);
}

$style['height'] = $height;
$style['height'] = self::convertHtmlSize($attribute->value);
$style['unit'] = \PhpOffice\PhpWord\Style\Image::UNIT_PX;

break;
Expand Down Expand Up @@ -1211,4 +1187,22 @@ private static function convertRgb(string $rgb): string

return trim($rgb, '# ');
}

/**
* Transform HTML sizes (pt, px) in pixels.
*/
protected static function convertHtmlSize(string $size): float
{
// pt
if (false !== strpos($size, 'pt')) {
return Converter::pointToPixel((float) str_replace('pt', '', $size));
}

// px
if (false !== strpos($size, 'px')) {
return (float) str_replace('px', '', $size);
}

return (float) $size;
}
}
57 changes: 44 additions & 13 deletions tests/PhpWordTests/Shared/HtmlTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
use PhpOffice\PhpWord\Shared\Html;
use PhpOffice\PhpWord\SimpleType\Jc;
use PhpOffice\PhpWord\SimpleType\LineSpacingRule;
use PhpOffice\PhpWord\SimpleType\TblWidth;
use PhpOffice\PhpWord\Style\Paragraph;
use PhpOffice\PhpWordTests\AbstractWebServerEmbedded;
use PhpOffice\PhpWordTests\TestHelperDOCX;
Expand Down Expand Up @@ -156,11 +157,11 @@ public function testParseStyleTableClassName(): void
}

/**
* Test underline.
* Test text-decoration style.
*/
public function testParseUnderline(): void
public function testParseTextDecoration(): void
{
$html = '<u>test</u>';
$html = '<span style="text-decoration: underline;">test</span>';
$phpWord = new PhpWord();
$section = $phpWord->addSection();
Html::addHtml($section, $html);
Expand All @@ -171,11 +172,11 @@ public function testParseUnderline(): void
}

/**
* Test text-decoration style.
* Test underline.
*/
public function testParseTextDecoration(): void
public function testParseUnderline(): void
{
$html = '<span style="text-decoration: underline;">test</span>';
$html = '<u>test</u>';
$phpWord = new PhpWord();
$section = $phpWord->addSection();
Html::addHtml($section, $html);
Expand All @@ -185,6 +186,25 @@ public function testParseTextDecoration(): void
self::assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val'));
}

/**
* Test width.
*
* @dataProvider providerParseWidth
*/
public function testParseWidth(string $htmlSize, float $docxSize, string $docxUnit): void
{
$html = '<table width="' . $htmlSize . '"><tr><td>A</td></tr></table>';
$phpWord = new PhpWord();
$section = $phpWord->addSection();

Html::addHtml($section, $html);
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
$xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals($docxSize, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals($docxUnit, $doc->getElement($xpath)->getAttribute('w:type'));
}

/**
* Test font-variant style.
*/
Expand Down Expand Up @@ -461,31 +481,31 @@ public function testParseTableAndCellWidth(): void
$xpath = '/w:document/w:body/w:tbl/w:tblGrid/w:gridCol';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));

// <td style="width: 25%; ...
$xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tcPr/w:tcW';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(25 * 50, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('pct', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type'));

// <table width="400" .. 400px = 6000 twips (400 / 96 * 1440)
$xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr/w:tc/w:tcPr/w:tcW';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(6000, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));

// <th style="width: 50pt; .. 50pt = 750 twips (50 / 72 * 1440)
$xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr[2]/w:tc[2]/w:tcPr/w:tcW';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(1000, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));

// <th width="300" .. 300px = 4500 twips (300 / 96 * 1440)
$xpath = '/w:document/w:body/w:tbl/w:tr/w:tc/w:tbl/w:tr[3]/w:tc/w:tcPr/w:tcW';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(4500, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));
}

/**
Expand Down Expand Up @@ -599,7 +619,7 @@ public function testParseTableCellspacingRowBgColor(): void
$xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblCellSpacing';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(3 * 15, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('dxa', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::TWIP, $doc->getElement($xpath)->getAttribute('w:type'));

$xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd';
self::assertTrue($doc->elementExists($xpath));
Expand Down Expand Up @@ -632,7 +652,7 @@ public function testParseTableStyleAttributeInlineStyle(): void
$xpath = '/w:document/w:body/w:tbl/w:tblPr/w:tblW';
self::assertTrue($doc->elementExists($xpath));
self::assertEquals(100 * 50, $doc->getElement($xpath)->getAttribute('w:w'));
self::assertEquals('pct', $doc->getElement($xpath)->getAttribute('w:type'));
self::assertEquals(TblWidth::PERCENT, $doc->getElement($xpath)->getAttribute('w:type'));

$xpath = '/w:document/w:body/w:tbl/w:tr[1]/w:tc[1]/w:tcPr/w:shd';
self::assertTrue($doc->elementExists($xpath));
Expand Down Expand Up @@ -1225,4 +1245,15 @@ public function testDontDecodeAlreadyEncodedDoubleQuotes(): void
$doc = TestHelperDOCX::getDocument($phpWord, 'Word2007');
self::assertIsObject($doc);
}

public static function providerParseWidth(): array
{
return [
['auto', 5000, TblWidth::PERCENT],
['100%', 5000, TblWidth::PERCENT],
['200pt', 3999.999999999999, TblWidth::TWIP],
['300px', 4500, TblWidth::TWIP],
['400', 6000, TblWidth::TWIP],
];
}
}

0 comments on commit f9da10e

Please sign in to comment.