From 58c6c52ee94b5b1821f9c2fad7ee415fd4fca1c6 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 23 May 2018 18:22:54 +0200 Subject: [PATCH 1/9] merged with local version --- src/PhpWord/Shared/Html.php | 51 +++++++++++++++++++++++++++-- tests/PhpWord/Shared/HtmlTest.php | 54 +++++++++++++++++++++++++++++++ 2 files changed, 103 insertions(+), 2 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index cbdcecd537..b308ec3e4d 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -22,6 +22,7 @@ use PhpOffice\PhpWord\Element\Table; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; +use PhpOffice\PhpWord\Settings; /** * Common Html functions @@ -32,6 +33,7 @@ class Html { private static $listIndex = 0; private static $xpath; + private static $options; /** * Add HTML parts. @@ -44,13 +46,17 @@ class Html * @param string $html The code to parse * @param bool $fullHTML If it's a full HTML, no need to add 'body' tag * @param bool $preserveWhiteSpace If false, the whitespaces between nodes will be removed + * @param array $options: + * + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally + * + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally */ - public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null ) { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, * which could be applied when such an element occurs in the parseNode function. */ + self::$options = $options; // Preprocess: remove all line ends, decode HTML entity, // fix ampersand and angle brackets and add body tag for HTML fragments @@ -141,6 +147,7 @@ protected static function parseNode($node, $element, $styles = array(), $data = 'sup' => array('Property', null, null, $styles, null, 'superScript', true), 'sub' => array('Property', null, null, $styles, null, 'subScript', true), 'span' => array('Span', $node, null, $styles, null, null, null), + 'font' => array('Span', $node, null, $styles, null, null, null), 'table' => array('Table', $node, $element, $styles, null, null, null), 'tr' => array('Row', $node, $element, $styles, null, null, null), 'td' => array('Cell', $node, $element, $styles, null, null, null), @@ -296,8 +303,9 @@ private static function parseSpan($node, &$styles) * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ - private static function parseTable($node, $element, &$styles) + private static function parseTable($node, $element, &$styles ) { + $elementStyles = self::parseInlineStyle($node, $styles['table']); $newElement = $element->addTable($elementStyles); @@ -648,6 +656,45 @@ private static function parseImage($node, $element) break; } } + if( strpos( $src, "data:image" ) !== false ){ + if( ! is_dir( self::$imgdir ) ) + mkdir( self::$imgdir ) ; + + $match = array(); + preg_match( '/data:image\/(\w+);base64,(.+)/', $src, $match ); + + $src = $imgFile = self::$imgdir . uniqid() . "." . $match[1]; + + $ifp = fopen( $imgFile, "wb"); + + fwrite($ifp, base64_decode( $match[2] ) ); + fclose($ifp); + + } + $src= urldecode($src); + + if( ! is_file( $src ) + && !is_null(self::$options) + && isset(self::$options['IMG_SRC_SEARCH']) + && isset(self::$options['IMG_SRC_REPLACE'])){ + $src = str_replace( self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src ); + } + + if(! is_file($src)){ + if($imgBlob=file_get_contents($src)){ + $tmpDir= Settings::getTempDir().'/'; + if( ! is_dir( $tmpDir ) ) + mkdir( $tmpDir ) ; + $match = array(); + preg_match( '/.+\.(\w+)$/', $src, $match ); + $src = $tmpDir . uniqid() . "." . $match[1]; + + $ifp = fopen( $src, "wb"); + + fwrite($ifp, $imgBlob ); + fclose($ifp); + } + } $newElement = $element->addImage($src, $style); return $newElement; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index b61418e01c..63295d6252 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -115,6 +115,20 @@ public function testParseTextDecoration() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** + * Test font + */ + public function testParseFont() + { + $html = 'test'; + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr')); + //TODO check style + } /** * Test line-height style @@ -447,6 +461,46 @@ public function testParseImage() $this->assertStringMatchesFormat('%Smso-position-horizontal:left%S', $doc->getElementAttribute($baseXpath . '[2]/w:pict/v:shape', 'style')); } + /** + * Test parsing of remote img + */ + public function testParseRemoteImage() + { + $src = 'https://phpword.readthedocs.io/en/latest/_images/phpword.png'; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

'; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + /** + * Test parsing of remote img that can be found locally + */ + public function testParseRemoteLocalImage() + { + $src = 'https://fakedomain.io/images/firefox.png'; + $localPath = __DIR__ . '/../_files/images/'; + $options= [ + 'IMG_SRC_SEARCH'=> 'https://fakedomain.io/images/', + 'IMG_SRC_REPLACE'=> $localPath + ]; + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

'; + Html::addHtml($section, $html, false, true, $options); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + public function testParseLink() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); From d54cc6efeea1a43419d9b97a759a796c1124aa6e Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 23 May 2018 18:35:12 +0200 Subject: [PATCH 2/9] fix lint --- samples/resources/Sample_30_ReadHTML.html | 6 ++++++ tests/PhpWord/Shared/HtmlTest.php | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index 5593298bfb..ea98221874 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -11,5 +11,11 @@

Adding element via HTML

Ordered (numbered) list:

  1. Item 1
  2. Item 2
+ + +

Double height

+ +

Includes images

+ diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 63295d6252..9b5def8525 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -485,10 +485,10 @@ public function testParseRemoteLocalImage() { $src = 'https://fakedomain.io/images/firefox.png'; $localPath = __DIR__ . '/../_files/images/'; - $options= [ + $options= array( 'IMG_SRC_SEARCH'=> 'https://fakedomain.io/images/', 'IMG_SRC_REPLACE'=> $localPath - ]; + ); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From a228811a611fe015c3bdb916d33ec579aa5697b4 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Wed, 23 May 2018 18:48:28 +0200 Subject: [PATCH 3/9] fixes --- src/PhpWord/Shared/Html.php | 72 +++++++++++++++---------------- tests/PhpWord/Shared/HtmlTest.php | 8 ++-- 2 files changed, 41 insertions(+), 39 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index b308ec3e4d..24f695c790 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -20,9 +20,9 @@ use PhpOffice\PhpWord\Element\AbstractContainer; use PhpOffice\PhpWord\Element\Row; use PhpOffice\PhpWord\Element\Table; +use PhpOffice\PhpWord\Settings; use PhpOffice\PhpWord\SimpleType\Jc; use PhpOffice\PhpWord\SimpleType\NumberFormat; -use PhpOffice\PhpWord\Settings; /** * Common Html functions @@ -50,7 +50,7 @@ class Html * + IMG_SRC_SEARCH: optional to speed up images loading from remote url when files can be found locally * + IMG_SRC_REPLACE: optional to speed up images loading from remote url when files can be found locally */ - public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null ) + public static function addHtml($element, $html, $fullHTML = false, $preserveWhiteSpace = true, $options = null) { /* * @todo parse $stylesheet for default styles. Should result in an array based on id, class and element, @@ -303,9 +303,8 @@ private static function parseSpan($node, &$styles) * * @todo As soon as TableItem, RowItem and CellItem support relative width and height */ - private static function parseTable($node, $element, &$styles ) + private static function parseTable($node, $element, &$styles) { - $elementStyles = self::parseInlineStyle($node, $styles['table']); $newElement = $element->addTable($elementStyles); @@ -656,45 +655,46 @@ private static function parseImage($node, $element) break; } } - if( strpos( $src, "data:image" ) !== false ){ - if( ! is_dir( self::$imgdir ) ) - mkdir( self::$imgdir ) ; - - $match = array(); - preg_match( '/data:image\/(\w+);base64,(.+)/', $src, $match ); + if (strpos($src, 'data:image') !== false) { + if (!is_dir(self::$imgdir)) { + mkdir(self::$imgdir); + } - $src = $imgFile = self::$imgdir . uniqid() . "." . $match[1]; + $match = array(); + preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); - $ifp = fopen( $imgFile, "wb"); + $src = $imgFile = self::$imgdir . uniqid() . '.' . $match[1]; - fwrite($ifp, base64_decode( $match[2] ) ); - fclose($ifp); + $ifp = fopen($imgFile, 'wb'); - } - $src= urldecode($src); + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } + $src = urldecode($src); - if( ! is_file( $src ) + if (!is_file($src) && !is_null(self::$options) && isset(self::$options['IMG_SRC_SEARCH']) - && isset(self::$options['IMG_SRC_REPLACE'])){ - $src = str_replace( self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src ); - } - - if(! is_file($src)){ - if($imgBlob=file_get_contents($src)){ - $tmpDir= Settings::getTempDir().'/'; - if( ! is_dir( $tmpDir ) ) - mkdir( $tmpDir ) ; - $match = array(); - preg_match( '/.+\.(\w+)$/', $src, $match ); - $src = $tmpDir . uniqid() . "." . $match[1]; - - $ifp = fopen( $src, "wb"); - - fwrite($ifp, $imgBlob ); - fclose($ifp); - } - } + && isset(self::$options['IMG_SRC_REPLACE'])) { + $src = str_replace(self::$options['IMG_SRC_SEARCH'], self::$options['IMG_SRC_REPLACE'], $src); + } + + if (!is_file($src)) { + if ($imgBlob = file_get_contents($src)) { + $tmpDir = Settings::getTempDir() . '/'; + if (!is_dir($tmpDir)) { + mkdir($tmpDir); + } + $match = array(); + preg_match('/.+\.(\w+)$/', $src, $match); + $src = $tmpDir . uniqid() . '.' . $match[1]; + + $ifp = fopen($src, 'wb'); + + fwrite($ifp, $imgBlob); + fclose($ifp); + } + } $newElement = $element->addImage($src, $style); return $newElement; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 9b5def8525..8c42544d52 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -115,6 +115,7 @@ public function testParseTextDecoration() $this->assertTrue($doc->elementExists('/w:document/w:body/w:p/w:r/w:rPr/w:u')); $this->assertEquals('single', $doc->getElementAttribute('/w:document/w:body/w:p/w:r/w:rPr/w:u', 'w:val')); } + /** * Test font */ @@ -478,6 +479,7 @@ public function testParseRemoteImage() $baseXpath = '/w:document/w:body/w:p/w:r'; $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** * Test parsing of remote img that can be found locally */ @@ -485,9 +487,9 @@ public function testParseRemoteLocalImage() { $src = 'https://fakedomain.io/images/firefox.png'; $localPath = __DIR__ . '/../_files/images/'; - $options= array( - 'IMG_SRC_SEARCH'=> 'https://fakedomain.io/images/', - 'IMG_SRC_REPLACE'=> $localPath + $options = array( + 'IMG_SRC_SEARCH' => 'https://fakedomain.io/images/', + 'IMG_SRC_REPLACE' => $localPath, ); $phpWord = new \PhpOffice\PhpWord\PhpWord(); From 46b7bea0975eb70a4cd6d8469d7fa859e277ec6e Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Thu, 24 May 2018 07:19:45 +0200 Subject: [PATCH 4/9] increased test coverage of new lines --- src/PhpWord/Shared/Html.php | 9 ++------- tests/PhpWord/Shared/HtmlTest.php | 16 ++++++++++++++++ 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 24f695c790..97b2701875 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -656,14 +656,12 @@ private static function parseImage($node, $element) } } if (strpos($src, 'data:image') !== false) { - if (!is_dir(self::$imgdir)) { - mkdir(self::$imgdir); - } + $tmpDir = Settings::getTempDir() . '/'; $match = array(); preg_match('/data:image\/(\w+);base64,(.+)/', $src, $match); - $src = $imgFile = self::$imgdir . uniqid() . '.' . $match[1]; + $src = $imgFile = $tmpDir . uniqid() . '.' . $match[1]; $ifp = fopen($imgFile, 'wb'); @@ -682,9 +680,6 @@ private static function parseImage($node, $element) if (!is_file($src)) { if ($imgBlob = file_get_contents($src)) { $tmpDir = Settings::getTempDir() . '/'; - if (!is_dir($tmpDir)) { - mkdir($tmpDir); - } $match = array(); preg_match('/.+\.(\w+)$/', $src, $match); $src = $tmpDir . uniqid() . '.' . $match[1]; diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 8c42544d52..6925e3c20e 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -480,6 +480,22 @@ public function testParseRemoteImage() $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** + * Test parsing embedded image + */ + public function testParseEmbeddedImage() + { + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

'; + Html::addHtml($section, $html); + + $doc = TestHelperDOCX::getDocument($phpWord, 'Word2007'); + + $baseXpath = '/w:document/w:body/w:p/w:r'; + $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); + } + /** * Test parsing of remote img that can be found locally */ From a89e4c93a78c964bd3b7e6dc5f1ab38bb0d18525 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Fri, 25 May 2018 08:01:17 +0200 Subject: [PATCH 5/9] added exception control to file_get_contents error --- samples/resources/Sample_30_ReadHTML.html | 6 +++++- samples/results/.gitignore | 0 src/PhpWord/Shared/Html.php | 10 ++++++++-- tests/PhpWord/Shared/HtmlTest.php | 14 ++++++++++++++ 4 files changed, 27 insertions(+), 3 deletions(-) mode change 100644 => 100755 samples/results/.gitignore diff --git a/samples/resources/Sample_30_ReadHTML.html b/samples/resources/Sample_30_ReadHTML.html index ea98221874..b3d2fad222 100644 --- a/samples/resources/Sample_30_ReadHTML.html +++ b/samples/resources/Sample_30_ReadHTML.html @@ -12,10 +12,14 @@

Adding element via HTML

Ordered (numbered) list:

  1. Item 1
  2. Item 2
-

Double height

Includes images

+ + + + + diff --git a/samples/results/.gitignore b/samples/results/.gitignore old mode 100644 new mode 100755 diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 97b2701875..231727693c 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -655,6 +655,7 @@ private static function parseImage($node, $element) break; } } + $origin_src= $src; if (strpos($src, 'data:image') !== false) { $tmpDir = Settings::getTempDir() . '/'; @@ -678,7 +679,7 @@ private static function parseImage($node, $element) } if (!is_file($src)) { - if ($imgBlob = file_get_contents($src)) { + if ($imgBlob = @file_get_contents($src)) { $tmpDir = Settings::getTempDir() . '/'; $match = array(); preg_match('/.+\.(\w+)$/', $src, $match); @@ -690,7 +691,12 @@ private static function parseImage($node, $element) fclose($ifp); } } - $newElement = $element->addImage($src, $style); + + if (is_file($src)){ + $newElement = $element->addImage($src, $style); + }else{ + throw new \Exception("Could not load image $origin_src"); + } return $newElement; } diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 6925e3c20e..481b5d75bc 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -519,6 +519,20 @@ public function testParseRemoteLocalImage() $this->assertTrue($doc->elementExists($baseXpath . '/w:pict/v:shape')); } + /** + * Test parsing of remote img that can be found locally + */ + public function testCouldNotLoadImage() + { + $src = 'https://fakedomain.io/images/firefox.png'; + $this->expectException(\Exception::class); + + $phpWord = new \PhpOffice\PhpWord\PhpWord(); + $section = $phpWord->addSection(); + $html = '

'; + Html::addHtml($section, $html, false, true); + } + public function testParseLink() { $phpWord = new \PhpOffice\PhpWord\PhpWord(); From 65a594d2713b6ff876ca0a1d230404a0d160b6c9 Mon Sep 17 00:00:00 2001 From: Javier Garcia Date: Fri, 25 May 2018 09:29:58 +0200 Subject: [PATCH 6/9] cs-fixer fixes --- src/PhpWord/Shared/Html.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 231727693c..58ce241288 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -655,7 +655,7 @@ private static function parseImage($node, $element) break; } } - $origin_src= $src; + $originSrc = $src; if (strpos($src, 'data:image') !== false) { $tmpDir = Settings::getTempDir() . '/'; @@ -692,10 +692,10 @@ private static function parseImage($node, $element) } } - if (is_file($src)){ - $newElement = $element->addImage($src, $style); - }else{ - throw new \Exception("Could not load image $origin_src"); + if (is_file($src)) { + $newElement = $element->addImage($src, $style); + } else { + throw new \Exception("Could not load image $originSrc"); } return $newElement; From da604a80c43241b28c7cf6d07977f1533a70d39c Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 27 May 2018 20:53:42 +0200 Subject: [PATCH 7/9] use annotation instead --- tests/PhpWord/Shared/HtmlTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/PhpWord/Shared/HtmlTest.php b/tests/PhpWord/Shared/HtmlTest.php index 481b5d75bc..32f4bf460c 100644 --- a/tests/PhpWord/Shared/HtmlTest.php +++ b/tests/PhpWord/Shared/HtmlTest.php @@ -521,11 +521,12 @@ public function testParseRemoteLocalImage() /** * Test parsing of remote img that can be found locally + * + * @expectedException \Exception */ public function testCouldNotLoadImage() { $src = 'https://fakedomain.io/images/firefox.png'; - $this->expectException(\Exception::class); $phpWord = new \PhpOffice\PhpWord\PhpWord(); $section = $phpWord->addSection(); From c22f7eab5e2a9e764946ddf77c8f82d21811871a Mon Sep 17 00:00:00 2001 From: troosan Date: Sun, 27 May 2018 21:27:45 +0200 Subject: [PATCH 8/9] add check on opened file --- src/PhpWord/Shared/Html.php | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/PhpWord/Shared/Html.php b/src/PhpWord/Shared/Html.php index 58ce241288..239cfd1dbb 100644 --- a/src/PhpWord/Shared/Html.php +++ b/src/PhpWord/Shared/Html.php @@ -666,8 +666,10 @@ private static function parseImage($node, $element) $ifp = fopen($imgFile, 'wb'); - fwrite($ifp, base64_decode($match[2])); - fclose($ifp); + if ($ifp !== false) { + fwrite($ifp, base64_decode($match[2])); + fclose($ifp); + } } $src = urldecode($src); @@ -687,8 +689,10 @@ private static function parseImage($node, $element) $ifp = fopen($src, 'wb'); - fwrite($ifp, $imgBlob); - fclose($ifp); + if ($ifp !== false) { + fwrite($ifp, $imgBlob); + fclose($ifp); + } } } From e76487172b78af26e44b250f85d41fce541f5084 Mon Sep 17 00:00:00 2001 From: troosan Date: Thu, 31 May 2018 00:31:41 +0200 Subject: [PATCH 9/9] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index dfcce5a4d2..e7b7ed6869 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ v0.15.0 (?? ??? 2018) - Add support for table indent (tblInd) @Trainmaster #1343 - Added parsing of internal links in HTML reader @lalop #1336 - Several improvements to charts @JAEK-S #1332 +- Add parsing of html image in base64 format @jgpATs2w #1382 ### Fixed - Fix reading of docx default style - @troosan #1238