From fcaeadac95c4756412ee5bfe43b074362137f2a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Ko=C5=84?= Date: Wed, 17 Aug 2022 10:24:16 +0200 Subject: [PATCH 01/13] Fixed #13957 --- lib/Page.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Page.php b/lib/Page.php index 8dd63f5..efcb9f8 100644 --- a/lib/Page.php +++ b/lib/Page.php @@ -1147,7 +1147,7 @@ protected function divideTable(Box $tableChild, string $yPos, Box $cloned) if ($row->getRowSpanUp() > 0) { $move = []; // copy spanned rows too - for ($i = $row->getRowSpanUp(); $i >= 0; --$i) { + for ($i = $row->getRowSpanUp(); $i > 0; --$i) { $spannedRowIndex = $rowIndex - $i; $move[] = $tableRowGroup->getChildren()[$spannedRowIndex]; } From 310a8cebd0537d26fa80a2a3c5aec5e1d95410c7 Mon Sep 17 00:00:00 2001 From: Mariusz Krzaczkowski Date: Thu, 6 Oct 2022 07:56:41 +0200 Subject: [PATCH 02/13] Update README.MD --- README.MD | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.MD b/README.MD index 499d426..f70f1ad 100644 --- a/README.MD +++ b/README.MD @@ -8,6 +8,9 @@ ## PDF generation library for PHP The best library in the world to generate PDF from HTML +## Issues & bugs +Report errors related to PDF in https://github.com/YetiForceCompany/YetiForceCRM/issues + ## Basic usage (for more take a look at examples folder) ```php From ceb9dfd32bdac71368a76e40679f1e452dd5a679 Mon Sep 17 00:00:00 2001 From: Mariusz Krzaczkowski Date: Thu, 6 Oct 2022 07:57:09 +0200 Subject: [PATCH 03/13] Update README.MD --- README.MD | 1 - 1 file changed, 1 deletion(-) diff --git a/README.MD b/README.MD index f70f1ad..1152aa1 100644 --- a/README.MD +++ b/README.MD @@ -2,7 +2,6 @@ [![Latest Stable Version](https://poser.pugx.org/yetiforce/yetiforcepdf/v/stable)](https://packagist.org/packages/yetiforce/yetiforcepdf) [![Build Status](https://travis-ci.org/YetiForceCompany/YetiForcePDF.svg?branch=developer)](https://travis-ci.org/YetiForceCompany/YetiForcePDF) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/YetiForceCompany/YetiForcePDF/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/YetiForceCompany/YetiForcePDF/?branch=master) -[![Codacy Badge](https://api.codacy.com/project/badge/Grade/b2e8645f5091496089ed203d05a05d61)](https://app.codacy.com/app/mariuszkrzaczkowski/YetiForcePDF?utm_source=github.com&utm_medium=referral&utm_content=YetiForceCompany/YetiForcePDF&utm_campaign=Badge_Grade_Settings) [![Maintainability](https://api.codeclimate.com/v1/badges/af478ddd07cf7278841a/maintainability)](https://codeclimate.com/github/YetiForceCompany/YetiForcePDF/maintainability) ## PDF generation library for PHP From 4b3f64ce6cc9454d33838d7a3362dfab35b27379 Mon Sep 17 00:00:00 2001 From: Claude Diderich Date: Wed, 12 Oct 2022 19:51:17 +0200 Subject: [PATCH 04/13] Default originalSize and originalUnit to 0 to avoid warning message --- lib/Style/Normalizer/Border.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Style/Normalizer/Border.php b/lib/Style/Normalizer/Border.php index 8f18cea..1f176a7 100644 --- a/lib/Style/Normalizer/Border.php +++ b/lib/Style/Normalizer/Border.php @@ -25,8 +25,8 @@ public function normalize($ruleValue, string $ruleName = ''): array } $matches = []; preg_match('/([0-9]+)([a-z]+)\s+(solid|dashed|dotted|none)\s+(.+)?/ui', $ruleValue, $matches); - $originalSize = $matches[1]; - $originalUnit = $matches[2]; + $originalSize = $matches[1] = 0; + $originalUnit = $matches[2] = 0; if (isset($matches[3])) { $style = $matches[3]; } else { From d088d95e7f98cd00b96942d446121ce9269c07d3 Mon Sep 17 00:00:00 2001 From: Claude Diderich Date: Wed, 12 Oct 2022 20:23:43 +0200 Subject: [PATCH 05/13] Default originalSize and originalUnit to 0 to avoid warning message --- lib/Style/Normalizer/Border.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Style/Normalizer/Border.php b/lib/Style/Normalizer/Border.php index 1f176a7..13d8759 100644 --- a/lib/Style/Normalizer/Border.php +++ b/lib/Style/Normalizer/Border.php @@ -25,8 +25,8 @@ public function normalize($ruleValue, string $ruleName = ''): array } $matches = []; preg_match('/([0-9]+)([a-z]+)\s+(solid|dashed|dotted|none)\s+(.+)?/ui', $ruleValue, $matches); - $originalSize = $matches[1] = 0; - $originalUnit = $matches[2] = 0; + $originalSize = $matches[1] ?? 0; + $originalUnit = $matches[2] ?? 0; if (isset($matches[3])) { $style = $matches[3]; } else { From de5b4f796da293cecee744b41bab9cb0e5303c9f Mon Sep 17 00:00:00 2001 From: Mariusz Krzaczkowski Date: Tue, 7 Feb 2023 15:14:35 +0100 Subject: [PATCH 06/13] Update README.MD --- README.MD | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.MD b/README.MD index 1152aa1..82f41f8 100644 --- a/README.MD +++ b/README.MD @@ -198,3 +198,12 @@ When you want to place page number (in header or footer for example) you can do ## License Distributed under the MIT license. See LICENSE for details. + +## 👥 Contributors + +This project exists thanks to all the people who contribute. + + + + + From c766e2991734b2c5335001e7e4b38993083194e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adrian=20Ko=C5=84?= Date: Tue, 14 Mar 2023 12:03:58 +0100 Subject: [PATCH 07/13] Revert changes with adding startxref to pdf --- lib/Document.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Document.php b/lib/Document.php index 4e8da32..2b70277 100644 --- a/lib/Document.php +++ b/lib/Document.php @@ -893,11 +893,11 @@ public function render(): string $trailer = (new \YetiForcePDF\Objects\Trailer()) ->setDocument($this)->setRootObject($this->catalog)->setSize($objectSize); $this->buffer .= $trailer->render() . "\n"; - // $this->buffer .= implode("\n", [ - // 'startxref', - // $offset, - // '', - // ]); + $this->buffer .= implode("\n", [ + 'startxref', + $offset, + '', + ]); $this->buffer .= $this->getDocumentFooter(); $this->removeObject($trailer); return $this->buffer; From 6927c0012f42adcf4399d84b8fe753f01e00bfc2 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 05:35:56 +0000 Subject: [PATCH 08/13] Update dependency milon/barcode to v11 --- composer.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/composer.json b/composer.json index 1ab74c6..f6b4fc1 100644 --- a/composer.json +++ b/composer.json @@ -28,7 +28,7 @@ "phenx/php-font-lib": "^0.5", "guzzlehttp/guzzle": "^7", "composer/ca-bundle": "^1", - "milon/barcode": "^9", + "milon/barcode": "^11", "sabberworm/php-css-parser": "^8" }, "autoload": { From f9a8b8a1da3a1917cc9122cd33f6ffb8f2b7650d Mon Sep 17 00:00:00 2001 From: bwnek Date: Fri, 8 Mar 2024 11:33:57 +0100 Subject: [PATCH 09/13] refactor: add whitespace, change param visibility, remove unused return statement --- lib/Document.php | 36 ++++++++++++++++++++++++++++++++---- 1 file changed, 32 insertions(+), 4 deletions(-) diff --git a/lib/Document.php b/lib/Document.php index 2b70277..bb14414 100644 --- a/lib/Document.php +++ b/lib/Document.php @@ -31,34 +31,40 @@ class Document * @var int */ protected $actualId = 0; + /** * Main output buffer / content for pdf file. * * @var string */ protected $buffer = ''; + /** * Main entry point - root element. * * @var \YetiForcePDF\Catalog */ protected $catalog; + /** * Pages dictionary. * * @var Pages */ protected $pagesObject; + /** * Current page object. * * @var Page */ protected $currentPageObject; + /** * @var string default page format */ protected $defaultFormat = 'A4'; + /** * @var string default page orientation */ @@ -68,6 +74,7 @@ class Document * @var Page[] all pages in the document */ protected $pages = []; + /** * Default page margins. * @@ -79,68 +86,82 @@ class Document 'right' => 40, 'bottom' => 40, ]; + /** * All objects inside document. * * @var \YetiForcePDF\Objects\PdfObject[] */ protected $objects = []; + /** * @var \YetiForcePDF\Html\Parser */ protected $htmlParser; + /** * Fonts data. * * @var array */ protected $fontsData = []; + /** * @var array */ protected $fontInstances = []; + /** * Actual font id. * * @var int */ protected $actualFontId = 0; + /** * Actual graphic state id. * * @var int */ protected $actualGraphicStateId = 0; + /** * @var bool */ protected $debugMode = false; + /** * @var HeaderBox|null */ protected $header; + /** * @var FooterBox|null */ protected $footer; + /** * @var WatermarkBox|null */ protected $watermark; + /** * @var Meta */ protected $meta; + /** * @var bool */ protected $parsed = false; + /** * Characters int values cache for fonts. * * @var array */ - protected $ordCache = []; + public $ordCache = []; + /** * Css selectors like classes ids. * @@ -444,7 +465,7 @@ public function getFontData(string $family, string $weight, string $style) */ public static function addFonts(array $fonts) { - return \YetiForcePDF\Objects\Font::loadFromArray($fonts); + \YetiForcePDF\Objects\Font::loadFromArray($fonts); } /** @@ -872,10 +893,13 @@ public function parse() */ public function render(): string { - $xref = $this->buffer = ''; + $xref = ''; + $this->buffer = ''; + $this->buffer .= $this->getDocumentHeader(); $this->parse(); $objectSize = 0; + foreach ($this->objects as $object) { if (\in_array($object->getBasicType(), ['Dictionary', 'Stream', 'Array'])) { $xref .= sprintf("%010d 00000 n \n", \strlen($this->buffer)); @@ -883,6 +907,7 @@ public function render(): string ++$objectSize; } } + $offset = \strlen($this->buffer); $this->buffer .= implode("\n", [ 'xref', @@ -890,8 +915,10 @@ public function render(): string '0000000000 65535 f ', $xref, ]); + $trailer = (new \YetiForcePDF\Objects\Trailer()) ->setDocument($this)->setRootObject($this->catalog)->setSize($objectSize); + $this->buffer .= $trailer->render() . "\n"; $this->buffer .= implode("\n", [ 'startxref', @@ -900,6 +927,7 @@ public function render(): string ]); $this->buffer .= $this->getDocumentFooter(); $this->removeObject($trailer); + return $this->buffer; } @@ -910,7 +938,7 @@ public function render(): string * * @return array */ - public function getCssSelectorRules(string $selector) + public function getCssSelectorRules(string $selector): array { $rules = []; foreach (explode(' ', $selector) as $className) { From 67788acd5cc659f9f95eb61e27659dbb65e6d59e Mon Sep 17 00:00:00 2001 From: bwnek Date: Fri, 8 Mar 2024 11:41:15 +0100 Subject: [PATCH 10/13] refactor: change text decoding method --- lib/Html/Parser.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/Html/Parser.php b/lib/Html/Parser.php index 7b38e7d..8005787 100644 --- a/lib/Html/Parser.php +++ b/lib/Html/Parser.php @@ -1,6 +1,7 @@ html = $this->cleanUpHtml($html); - $this->html = mb_convert_encoding($this->html, 'HTML-ENTITIES', $fromEncoding); + $this->html = html_entity_decode($this->html, ENT_COMPAT, $fromEncoding); + return $this; } @@ -72,7 +77,7 @@ public function loadHtml(string $html, string $fromEncoding = ''): self * * @return string */ - public function getHtml() + public function getHtml(): string { return $this->html; } From d87fc0a52f1272e77d660e2c202ac63e47d50ad3 Mon Sep 17 00:00:00 2001 From: bwnek Date: Fri, 8 Mar 2024 11:41:51 +0100 Subject: [PATCH 11/13] refactor: add whitespace, add missing class param --- lib/Layout/TextBox.php | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/lib/Layout/TextBox.php b/lib/Layout/TextBox.php index 22690ee..080417b 100644 --- a/lib/Layout/TextBox.php +++ b/lib/Layout/TextBox.php @@ -1,6 +1,7 @@ style = (new \YetiForcePDF\Style\Style()) ->setDocument($this->document) ->setBox($this) ->init(); + return $this; } @@ -45,7 +50,7 @@ public function init() * * @return $this */ - public function setText(string $text) + public function setText(string $text): self { $this->text = $text; return $this; @@ -56,7 +61,7 @@ public function setText(string $text) * * @return string */ - public function getText() + public function getText(): string { return $this->text; } @@ -66,9 +71,10 @@ public function getText() * * @return $this */ - public function measureWidth() + public function measureWidth(): self { $this->getDimensions()->setWidth($this->getStyle()->getFont()->getTextWidth($this->getText())); + return $this; } @@ -77,9 +83,10 @@ public function measureWidth() * * @return $this */ - public function measureHeight() + public function measureHeight(): self { $this->getDimensions()->setHeight($this->getStyle()->getFont()->getTextHeight($this->getText())); + return $this; } @@ -88,10 +95,11 @@ public function measureHeight() * * @return $this */ - public function measureOffset() + public function measureOffset(): self { $this->getOffset()->setLeft('0'); $this->getOffset()->setTop('0'); + return $this; } @@ -100,11 +108,12 @@ public function measureOffset() * * @return $this */ - public function measurePosition() + public function measurePosition(): self { $parent = $this->getParent(); $this->getCoordinates()->setX(Math::add($parent->getCoordinates()->getX(), $this->getOffset()->getLeft())); $this->getCoordinates()->setY(Math::add($parent->getCoordinates()->getY(), $this->getOffset()->getTop())); + return $this; } @@ -139,6 +148,7 @@ public function getInstructions(): string $textHeight = $style->getFont()->getTextHeight(); $textContent = $this->document->filterText($this->getText()); $transform = $style->getTransformations($pdfX, $baseLineY); + $element = [ 'q', $graphicStateStr, @@ -150,7 +160,7 @@ public function getInstructions(): string 'ET', 'Q', ]; - $this->drawTextOutline = false; + if ($this->drawTextOutline) { $element = array_merge($element, [ 'q', @@ -162,6 +172,7 @@ public function getInstructions(): string 'Q', ]); } + return implode("\n", $element); } } From 2bdeb9e7c2facf09f11e8346f5cac96acd945aa2 Mon Sep 17 00:00:00 2001 From: bwnek Date: Wed, 13 Mar 2024 14:03:25 +0100 Subject: [PATCH 12/13] fix: improve char encoding --- lib/Document.php | 17 ++++++++++++----- lib/Html/Parser.php | 16 +++++++++++----- 2 files changed, 23 insertions(+), 10 deletions(-) diff --git a/lib/Document.php b/lib/Document.php index bb14414..13c8563 100644 --- a/lib/Document.php +++ b/lib/Document.php @@ -14,6 +14,8 @@ namespace YetiForcePDF; +use Exception; +use YetiForcePDF\Html\Parser; use YetiForcePDF\Layout\FooterBox; use YetiForcePDF\Layout\HeaderBox; use YetiForcePDF\Layout\WatermarkBox; @@ -95,7 +97,7 @@ class Document protected $objects = []; /** - * @var \YetiForcePDF\Html\Parser + * @var Parser */ protected $htmlParser; @@ -786,14 +788,19 @@ public function removeObject(PdfObject $object): self * Load html string. * * @param string $html - * @param string $inputEncoding + * @param string $fromEncoding * * @return $this + * @throws Exception */ - public function loadHtml(string $html, string $inputEncoding = 'UTF-8') + public function loadHtml(string $html, string $fromEncoding = 'UTF-8'): self { - $this->htmlParser = (new \YetiForcePDF\Html\Parser())->setDocument($this)->init(); - $this->htmlParser->loadHtml($html, $inputEncoding); + if ($fromEncoding === '') { + throw new Exception('Encoding can not be empty'); + } + + $this->htmlParser = (new Parser())->setDocument($this)->init(); + $this->htmlParser->loadHtml($html, $fromEncoding); return $this; } diff --git a/lib/Html/Parser.php b/lib/Html/Parser.php index 8005787..537b763 100644 --- a/lib/Html/Parser.php +++ b/lib/Html/Parser.php @@ -14,12 +14,13 @@ namespace YetiForcePDF\Html; +use YetiForcePDF\Base; use YetiForcePDF\Layout\PageGroupBox; /** * Class Parser. */ -class Parser extends \YetiForcePDF\Base +class Parser extends Base { /** * @var \DOMDocument @@ -61,13 +62,18 @@ protected function cleanUpHtml(string $html) * @param string $html * @param string $fromEncoding * - * @return \YetiForcePDF\Html\Parser + * @return Parser */ - public function loadHtml(string $html, string $fromEncoding = ''): self + public function loadHtml(string $html, string $fromEncoding): self { - $html = htmlspecialchars_decode($html, ENT_HTML5); + $this->html = htmlspecialchars_decode($html, ENT_HTML5); $this->html = $this->cleanUpHtml($html); - $this->html = html_entity_decode($this->html, ENT_COMPAT, $fromEncoding); + + // 0x80 - start of unicode range + // 0x10FFFF - end of unicode range + // 0 - do not ommit any unicode char + // ~0 - negated 0 - convert negation of nothing (so convert all) + $this->html = mb_encode_numericentity($this->html, [0x80, 0x10FFFF, 0, ~0], $fromEncoding); return $this; } From 341fbc2677db0349deaea778986c68aec7bc54aa Mon Sep 17 00:00:00 2001 From: bwnek Date: Fri, 22 Mar 2024 07:42:39 +0100 Subject: [PATCH 13/13] fix: change xref object size --- lib/Document.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Document.php b/lib/Document.php index bb14414..3af4c3e 100644 --- a/lib/Document.php +++ b/lib/Document.php @@ -911,7 +911,7 @@ public function render(): string $offset = \strlen($this->buffer); $this->buffer .= implode("\n", [ 'xref', - '0 ' . ($objectSize + 1), + '0 ' . $objectSize, '0000000000 65535 f ', $xref, ]);