diff --git a/src/CssConverter.php b/src/CssConverter.php index 8563bf5d..9465ad8e 100644 --- a/src/CssConverter.php +++ b/src/CssConverter.php @@ -307,6 +307,27 @@ public function convertBackgroundImage($css) return null; } + /** + * Parse a background size + * + * @param string $css + * + * @return string|null $value + */ + public function convertBackgroundSize($css) + { + if ($css === 'auto') { + return null; + } + + $available = ['contain', 'cover']; + if (in_array($css, $available)) { + return $css; + } + + return null; + } + /** * Parse a background position * diff --git a/src/Html2Pdf.php b/src/Html2Pdf.php index fb3c4b3f..1792c46c 100755 --- a/src/Html2Pdf.php +++ b/src/Html2Pdf.php @@ -1798,6 +1798,7 @@ protected function _drawRectangle($x, $y, $w, $h, $border, $padding, $margin, $b $iName = $background['image']; $iPosition = $background['position'] !== null ? $background['position'] : array(0, 0); $iRepeat = $background['repeat'] !== null ? $background['repeat'] : array(true, true); + $iSize = $background['size'] !== null ? $background['size'] : 'auto'; // size of the background without the borders $bX = $x; @@ -1806,93 +1807,126 @@ protected function _drawRectangle($x, $y, $w, $h, $border, $padding, $margin, $b $bH = $h; if ($border['b']['width']) { - $bH-= $border['b']['width']; + $bH -= $border['b']['width']; } if ($border['l']['width']) { - $bW-= $border['l']['width']; - $bX+= $border['l']['width']; + $bW -= $border['l']['width']; + $bX += $border['l']['width']; } if ($border['t']['width']) { - $bH-= $border['t']['width']; - $bY+= $border['t']['width']; + $bH -= $border['t']['width']; + $bY += $border['t']['width']; } if ($border['r']['width']) { - $bW-= $border['r']['width']; + $bW -= $border['r']['width']; } // get the size of the image - // WARNING : if URL, "allow_url_fopen" must turned to "on" in php.ini - $imageInfos=@getimagesize($iName); + // WARNING : if URL, "allow_url_fopen" must be turned to "on" in php.ini + $imageInfos = @getimagesize($iName); - // if the image can not be loaded - if (!is_array($imageInfos) || count($imageInfos)<2) { + // if the image cannot be loaded + if (!is_array($imageInfos) || count($imageInfos) < 2) { if ($this->_testIsImage) { - $e = new ImageException('Unable to get the size of the image ['.$iName.']'); + $e = new ImageException('Unable to get the size of the image [' . $iName . ']'); $e->setImage($iName); throw $e; } } else { - // convert the size of the image from pixel to the unit of the PDF - $imageWidth = 72./96.*$imageInfos[0]/$this->pdf->getK(); - $imageHeight = 72./96.*$imageInfos[1]/$this->pdf->getK(); + // convert the size of the image from pixels to the unit of the PDF + $imageWidth = 72. / 96. * $imageInfos[0] / $this->pdf->getK(); + $imageHeight = 72. / 96. * $imageInfos[1] / $this->pdf->getK(); + + // prepare for image size "contain" and "cover" + $fitbox = false; + $resize = false; + if ($iSize && $iSize != 'auto') { + $containerIsLandscape = $bW > $bH; + $imageIsLandscape = $imageWidth > $imageHeight; + + if ($iSize == 'contain') { + if (($containerIsLandscape && $imageIsLandscape) || (!$containerIsLandscape && !$imageIsLandscape)) { + // Scale to fit width or height, maintaining aspect ratio + $scale = min($bW / $imageWidth, $bH / $imageHeight); + } else { + // Scale to fit height or width, maintaining aspect ratio + $scale = min($bH / $imageHeight, $bW / $imageWidth); + } + $imageWidth *= $scale; + $imageHeight *= $scale; + } else if ($iSize == 'cover') { + if (($containerIsLandscape && $imageIsLandscape) || (!$containerIsLandscape && !$imageIsLandscape)) { + // Scale to cover width or height, maintaining aspect ratio + $scale = max($bW / $imageWidth, $bH / $imageHeight); + } else { + // Scale to cover height or width, maintaining aspect ratio + $scale = max($bH / $imageHeight, $bW / $imageWidth); + } + $imageWidth *= $scale; + $imageHeight *= $scale; + } + + $resize = true; + $fitbox = 'CM'; + } - // prepare the position of the backgroung + // prepare the position of the background if ($iRepeat[0]) { $iPosition[0] = $bX; } elseif (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[0], $match)) { - $iPosition[0] = $bX + $match[1]*($bW-$imageWidth)/100; + $iPosition[0] = $bX + $match[1] * ($bW - $imageWidth) / 100; } else { - $iPosition[0] = $bX+$iPosition[0]; + $iPosition[0] = $bX + $iPosition[0]; } if ($iRepeat[1]) { $iPosition[1] = $bY; } elseif (preg_match('/^([-]?[0-9\.]+)%/isU', $iPosition[1], $match)) { - $iPosition[1] = $bY + $match[1]*($bH-$imageHeight)/100; + $iPosition[1] = $bY + $match[1] * ($bH - $imageHeight) / 100; } else { - $iPosition[1] = $bY+$iPosition[1]; + $iPosition[1] = $bY + $iPosition[1]; } $imageXmin = $bX; - $imageXmax = $bX+$bW; + $imageXmax = $bX + $bW; $imageYmin = $bY; - $imageYmax = $bY+$bH; + $imageYmax = $bY + $bH; if (!$iRepeat[0] && !$iRepeat[1]) { - $imageXmin = $iPosition[0]; - $imageXmax = $iPosition[0]+$imageWidth; - $imageYmin = $iPosition[1]; - $imageYmax = $iPosition[1]+$imageHeight; + $imageXmin = $iPosition[0]; + $imageXmax = $iPosition[0] + $imageWidth; + $imageYmin = $iPosition[1]; + $imageYmax = $iPosition[1] + $imageHeight; } elseif ($iRepeat[0] && !$iRepeat[1]) { - $imageYmin = $iPosition[1]; - $imageYmax = $iPosition[1]+$imageHeight; + $imageYmin = $iPosition[1]; + $imageYmax = $iPosition[1] + $imageHeight; } elseif (!$iRepeat[0] && $iRepeat[1]) { - $imageXmin = $iPosition[0]; - $imageXmax = $iPosition[0]+$imageWidth; + $imageXmin = $iPosition[0]; + $imageXmax = $iPosition[0] + $imageWidth; } // build the path to display the image (because of radius) $this->pdf->clippingPathStart($bX, $bY, $bW, $bH, $inTL, $inTR, $inBL, $inBR); // repeat the image - for ($iY=$imageYmin; $iY<$imageYmax; $iY+=$imageHeight) { - for ($iX=$imageXmin; $iX<$imageXmax; $iX+=$imageWidth) { + for ($iY = $imageYmin; $iY < $imageYmax; $iY += $imageHeight) { + for ($iX = $imageXmin; $iX < $imageXmax; $iX += $imageWidth) { $cX = null; $cY = null; $cW = $imageWidth; $cH = $imageHeight; - if ($imageYmax-$iY<$imageHeight) { + if ($imageYmax - $iY < $imageHeight) { $cX = $iX; $cY = $iY; - $cH = $imageYmax-$iY; + $cH = $imageYmax - $iY; } - if ($imageXmax-$iX<$imageWidth) { + if ($imageXmax - $iX < $imageWidth) { $cX = $iX; $cY = $iY; - $cW = $imageXmax-$iX; + $cW = $imageXmax - $iX; } - $this->pdf->Image($iName, $iX, $iY, $imageWidth, $imageHeight, '', ''); + $this->pdf->Image($iName, $iX, $iY, $cW, $cH, '', '', '', $resize, 300, '', false, false, 0, $fitbox); } } diff --git a/src/Parsing/Css.php b/src/Parsing/Css.php index 8636b7a3..5a4f57df 100644 --- a/src/Parsing/Css.php +++ b/src/Parsing/Css.php @@ -172,7 +172,8 @@ public function initStyle() 'color' => null, 'image' => null, 'position' => null, - 'repeat' => null + 'repeat' => null, + 'size' => null ); $this->value['border'] = array(); $this->value['padding'] = array(); @@ -225,7 +226,7 @@ public function resetStyle($tagName = '') $this->value['display'] = null; $this->value['rotate'] = null; $this->value['overflow'] = 'visible'; - $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null); + $this->value['background'] = array('color' => null, 'image' => null, 'position' => null, 'repeat' => null, 'size' => null); $this->value['border'] = array( 't' => $this->readBorder('none'), 'r' => $this->readBorder('none'), @@ -1141,6 +1142,11 @@ public function analyse($tagName, &$param, $legacy = null) $this->value['background']['position'] = $this->cssConverter->convertBackgroundPosition($val, $res); break; + case 'background-size': + $res = null; + $this->value['background']['size'] = $this->cssConverter->convertBackgroundSize($val, $res); + break; + case 'background-repeat': $this->value['background']['repeat'] = $this->cssConverter->convertBackgroundRepeat($val); break;