N°5588 - Improve PDF export robustness when AttributeImage dimensions cannot be determined (#350)

Can happen for example on SVG images
Now the export won't crash anymore, and we'll get a log (export channel, warning level) with  the object and attribute causing a problem as context

Co-authored-by: Molkobain <lajarige.guillaume@free.fr>
This commit is contained in:
Pierre Goiffon
2023-02-23 11:45:29 +01:00
committed by GitHub
parent cac7e94a67
commit 822922df5c
2 changed files with 46 additions and 14 deletions

View File

@@ -549,6 +549,12 @@ class LogChannels
const DEADLOCK = 'DeadLock'; const DEADLOCK = 'DeadLock';
/**
* @var string
* @since 2.7.9
*/
const EXPORT = 'export';
const INLINE_IMAGE = 'InlineImage'; const INLINE_IMAGE = 'InlineImage';
/** /**

View File

@@ -216,28 +216,33 @@ EOF
// As sample data will be displayed in the web browser, AttributeImage needs to be rendered with a regular HTML format, meaning its "src" looking like "data:image/png;base64,iVBORw0KGgoAAAANSUh..." // As sample data will be displayed in the web browser, AttributeImage needs to be rendered with a regular HTML format, meaning its "src" looking like "data:image/png;base64,iVBORw0KGgoAAAANSUh..."
// Whereas for the PDF generation it needs to be rendered with a TCPPDF-compatible format, meaning its "src" looking like "@iVBORw0KGgoAAAANSUh..." // Whereas for the PDF generation it needs to be rendered with a TCPPDF-compatible format, meaning its "src" looking like "@iVBORw0KGgoAAAANSUh..."
if ($oAttDef instanceof AttributeImage) { if ($oAttDef instanceof AttributeImage) {
return $this->GetAttributeImageValue($oAttDef, $oObj->Get($sAttCode), static::ENUM_OUTPUT_TYPE_SAMPLE); return $this->GetAttributeImageValue($oObj, $sAttCode, static::ENUM_OUTPUT_TYPE_SAMPLE);
} }
} }
return parent::GetSampleData($oObj, $sAttCode); return parent::GetSampleData($oObj, $sAttCode);
} }
/**
* @param \DBObject $oObj
* @param string $sAttCode
*
* @return int|string
* @throws \Exception
*/
protected function GetValue($oObj, $sAttCode) protected function GetValue($oObj, $sAttCode)
{ {
switch($sAttCode) switch ($sAttCode) {
{
case 'id': case 'id':
$sRet = parent::GetValue($oObj, $sAttCode); $sRet = parent::GetValue($oObj, $sAttCode);
break; break;
default: default:
$value = $oObj->Get($sAttCode); $value = $oObj->Get($sAttCode);
if ($value instanceof ormDocument) if ($value instanceof ormDocument) {
{
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode); $oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
if ($oAttDef instanceof AttributeImage) if ($oAttDef instanceof AttributeImage)
{ {
$sRet = $this->GetAttributeImageValue($oAttDef, $value, static::ENUM_OUTPUT_TYPE_REAL); $sRet = $this->GetAttributeImageValue($oObj, $sAttCode, static::ENUM_OUTPUT_TYPE_REAL);
} }
else else
{ {
@@ -268,15 +273,22 @@ EOF
} }
/** /**
* @param \AttributeImage $oAttDef Instance of image attribute * @param \DBObject $oObj
* @param \ormDocument $oValue Value of image attribute * @param string $sAttCode
* @param string $sOutputType {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_SAMPLE}, {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_REAL} * @param string $sOutputType {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_SAMPLE}, {@see \PDFBulkExport::ENUM_OUTPUT_TYPE_REAL}
* *
* @return string Rendered value of $oAttDef / $oValue according to the desired $sOutputType * @return string Rendered value of $oAttDef / $oValue according to the desired $sOutputType
* @since 2.7.8 * @throws \ArchivedObjectException
* @throws \CoreException
*
* @since 2.7.8 N°2244 method creation
* @since 2.7.9 N°5588 signature change to get the object so that we can log all the needed information
*/ */
protected function GetAttributeImageValue(AttributeImage $oAttDef, ormDocument $oValue, string $sOutputType) protected function GetAttributeImageValue(DBObject $oObj, string $sAttCode, string $sOutputType)
{ {
$oValue = $oObj->Get($sAttCode);
$oAttDef = MetaModel::GetAttributeDef(get_class($oObj), $sAttCode);
// To limit the image size in the PDF output, we have to enforce the size as height/width because max-width/max-height have no effect // To limit the image size in the PDF output, we have to enforce the size as height/width because max-width/max-height have no effect
// //
$iDefaultMaxWidthPx = 48; $iDefaultMaxWidthPx = 48;
@@ -287,13 +299,27 @@ EOF
$sUrl = $oAttDef->Get('default_image'); $sUrl = $oAttDef->Get('default_image');
} else { } else {
list($iWidth, $iHeight) = utils::GetImageSize($oValue->GetData());
$iMaxWidthPx = min($iDefaultMaxWidthPx, $oAttDef->Get('display_max_width')); $iMaxWidthPx = min($iDefaultMaxWidthPx, $oAttDef->Get('display_max_width'));
$iMaxHeightPx = min($iDefaultMaxHeightPx, $oAttDef->Get('display_max_height')); $iMaxHeightPx = min($iDefaultMaxHeightPx, $oAttDef->Get('display_max_height'));
$fScale = min($iMaxWidthPx / $iWidth, $iMaxHeightPx / $iHeight); list($iWidth, $iHeight) = utils::GetImageSize($oValue->GetData());
$iNewWidth = $iWidth * $fScale; if ((is_null($iWidth)) || (is_null($iHeight)) || ($iWidth === 0) || ($iHeight === 0)) {
$iNewHeight = $iHeight * $fScale; // Avoid division by zero exception (SVGs, corrupted images, ...)
$iNewWidth = $iDefaultMaxWidthPx;
$iNewHeight = $iDefaultMaxHeightPx;
$sAttCode = $oAttDef->GetCode();
IssueLog::Warning('AttributeImage: Cannot read image size', LogChannels::EXPORT, [
'ObjClass' => get_class($oObj),
'ObjKey' => $oObj->GetKey(),
'ObjFriendlyName' => $oObj->GetName(),
'AttCode' => $sAttCode,
]);
} else {
$fScale = min($iMaxWidthPx / $iWidth, $iMaxHeightPx / $iHeight);
$iNewWidth = $iWidth * $fScale;
$iNewHeight = $iHeight * $fScale;
}
$sValueAsBase64 = base64_encode($oValue->GetData()); $sValueAsBase64 = base64_encode($oValue->GetData());
switch ($sOutputType) { switch ($sOutputType) {