From fd972b5b42e9ae9cac475ad82d3c98a455dbb1e9 Mon Sep 17 00:00:00 2001 From: "Benjamin D. Plessinger" Date: Fri, 21 Aug 2020 10:40:06 -0400 Subject: [PATCH] generate png and pdf from svg --- libraries/charting.php | 135 ++++++++++++++--------------------------- 1 file changed, 44 insertions(+), 91 deletions(-) diff --git a/libraries/charting.php b/libraries/charting.php index 878cfb79da..a26afb1148 100644 --- a/libraries/charting.php +++ b/libraries/charting.php @@ -57,47 +57,33 @@ function exportHighchart( $globalChartOptions = array_merge($globalChartOptions, $globalChartConfig); } $template = str_replace('_globalChartOptions_', json_encode($globalChartOptions), $template); - $template = str_replace('_width_',$effectiveWidth, $template); - $template = str_replace('_height_',$effectiveHeight, $template); - $data = getScreenFromChromium($template, $effectiveWidth, $effectiveHeight, $format === 'pdf' ? 'svg' : $format); - if($format === 'pdf'){ - $data = svg2pdf($data, round($width / 90.0 * 72.0), round($height / 90.0 * 72.0), $fileMetadata); + $template = str_replace('_width_', $effectiveWidth, $template); + $template = str_replace('_height_', $effectiveHeight, $template); + $svg = getSvgFromChromium($template, $effectiveWidth, $effectiveHeight); + switch($format){ + case 'png': + return convertSvg($svg, 'png', $effectiveWidth, $effectiveHeight, $fileMetadata); + break; + case 'pdf': + return convertSvg($svg, 'pdf', round($width / 90.0 * 72.0), round($height / 90.0 * 72.0), $fileMetadata); + break; + default: + return $svg; } - return $data; } /** - * Use Chromium to generate png or svg. - * - * For svg generation uses chromium repl + * Use Chromium to generate svg. * * @param string $html html that should be used by chromium * @param int $width desired width of output * @param int $height desired height of output - * @param string $format of output (png or svg) - * @param array $pdfExtras extras used for pdf output * - * @returns string contents of desired output + * @returns string svg * * @throws \Exception on invalid format, command execution failure, or non zero exit status */ -function getScreenFromChromium($html, $width, $height, $format){ - $repl = ''; - $outputFile = null; - if ($format == 'svg'){ - $repl = 'chart.getSVG(inputChartOptions);'; - $outputType = '-repl'; - } - elseif ($format == 'png'){ - $outputFile = tempnam(sys_get_temp_dir(), 'xdmod-chromiumScreenshot-'); - if ($outputFile === false) { - throw \Exception('Error creating temporary png file for chromium'); - } - $outputType = '--screenshot=' . $outputFile; - } - else { - throw new \Exception('Invalid format "' . $format . '" specified, must be one of svg, pdf, or png.'); - } +function getSvgFromChromium($html, $width, $height){ // Chromium requires the file to have a .html extension // cant use datauri as it will not execute embdeeded javascript @@ -118,7 +104,7 @@ function getScreenFromChromium($html, $width, $height, $format){ '--window-size=' . $width . ',' . $height, '--disable-extensions', '--incognito', - $outputType, + '-repl', $tmpHtmlFile ); $command = $chromiumPath . ' ' . implode(' ', $chromiumOptions); @@ -131,13 +117,11 @@ function getScreenFromChromium($html, $width, $height, $format){ $process = proc_open($command, $descriptor_spec, $pipes); if (!is_resource($process)) { @unlink($tmpHtmlFile); - @unlink($outputFile); throw new \Exception('Unable execute command: "'. $command . '". Details: ' . print_r(error_get_last(), true)); } - else { - fwrite($pipes[0], $repl); - fclose($pipes[0]); - } + fwrite($pipes[0], 'chart.getSVG(inputChartOptions);'); + fclose($pipes[0]); + $out = stream_get_contents($pipes[1]); $err = stream_get_contents($pipes[2]); fclose($pipes[1]); @@ -147,74 +131,45 @@ function getScreenFromChromium($html, $width, $height, $format){ @unlink($tmpHtmlFile); if ($return_value != 0) { - @unlink($outputFile); throw new \Exception('Unable execute command: "'. $command . '". Details: ' . $err); } - if (!empty($repl)){ - $result = json_decode(substr($out, 4, -6), true); - $data = $result['result']['value']; - } - else{ - $data = file_get_contents($outputFile); - @unlink($outputFile); - } - return $data; + $result = json_decode(substr($out, 4, -6), true); + return $result['result']['value']; } /** - * Use rsvg-convert to convert svg to pdf + * Use rsvg-convert to convert svg * * @param string $svgData string of the SVG - * @param int $width the new paper size in postscript points (72 ppi). - * @param int $height the new paper size in postscript points (72 ppi). - * @param array $metaData array containing metadata fields - * @return string contents of pdf - * @throws Exception when unable to execute or non-zero return code - */ - -function svg2pdf($svgData, $width, $height, $metaData){ - $command = 'rsvg-convert -w ' .$width. ' -h '.$height.' -f pdf'; - $pipes = array(); - $descriptor_spec = array( - 0 => array('pipe', 'r'), - 1 => array('pipe', 'w'), - 2 => array('pipe', 'w'), - ); - $process = proc_open($command, $descriptor_spec, $pipes); - if (!is_resource($process)) { - throw new \Exception('Unable execute command: "'. $command . '". Details: ' . print_r(error_get_last(), true)); - } - fwrite($pipes[0], $svgData); - fclose($pipes[0]); - $out = stream_get_contents($pipes[1]); - $err = stream_get_contents($pipes[2]); - - fclose($pipes[1]); - fclose($pipes[2]); - - $return_value = proc_close($process); - - if ($return_value != 0) { - throw new \Exception("$command returned $return_value, stdout: $out stderr: $err"); - } - return getPdfWithMetadata($out, $metaData); -} - -/** - * Use exiftool to set document metadata. - * - * @param string $pdf string representation of PDF file + * @param int $width desired width in proper size for format + * @param int $height desired height in proper size for format * @param array $docmeta array containing metadata fields * - * @return string PDF document + * @return string contents of the requested format + * @throws Exception when unable to execute or non-zero return code */ -function getPdfWithMetadata($pdf, $docmeta){ + +function convertSvg($svgData, $format, $width, $height, $docmeta){ $author = isset($docmeta['author']) ? addcslashes($docmeta['author'], "()\n\\") : 'XDMoD'; $subject = isset($docmeta['subject']) ? addcslashes($docmeta['subject'], "()\n\\") : 'XDMoD chart'; $title = isset($docmeta['title']) ? addcslashes($docmeta['title'], "()\n\\") :'XDMoD PDF chart export'; $creator = addcslashes('XDMoD ' . OPEN_XDMOD_VERSION, "()\n\\"); - $command = "exiftool -Title='$title' -Author='$author' -Subject='$subject' -Creator='$creator' -o - -"; + switch($format){ + case 'png': + $exifArgs = "-Title='$title' -Author='$author' -Description='$subject' -Source='$creator'"; + break; + case 'pdf': + $exifArgs = "-Title='$title' -Author='$author' -Subject='$subject' -Creator='$creator'"; + break; + default: + return $svgData; + } + + $rsvgCommand = 'rsvg-convert -w ' .$width. ' -h '.$height.' -f ' . $format; + $exifCommand = 'exiftool ' . $exifArgs . ' -o - -'; + + $command = $rsvgCommand . ' | ' . $exifCommand; $pipes = array(); $descriptor_spec = array( 0 => array('pipe', 'r'), @@ -222,13 +177,11 @@ function getPdfWithMetadata($pdf, $docmeta){ 2 => array('pipe', 'w'), ); $process = proc_open($command, $descriptor_spec, $pipes); - if (!is_resource($process)) { throw new \Exception('Unable execute command: "'. $command . '". Details: ' . print_r(error_get_last(), true)); } - fwrite($pipes[0], $pdf); + fwrite($pipes[0], $svgData); fclose($pipes[0]); - $out = stream_get_contents($pipes[1]); $err = stream_get_contents($pipes[2]);