Skip to content
21 changes: 21 additions & 0 deletions src/CssConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
Expand Down
106 changes: 70 additions & 36 deletions src/Html2Pdf.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}
}

Expand Down
10 changes: 8 additions & 2 deletions src/Parsing/Css.php
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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'),
Expand Down Expand Up @@ -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;
Expand Down