tcpdf/tests/src/PdfTools.php

199 lines
5.9 KiB
PHP

<?php
/**
* Helper class to execute PDF-related commands via shell
*
* @author Philippe Jausions
* @license http://www.gnu.org/copyleft/lesser.html GNU-LGPL v3 (see LICENSE.TXT)
*/
namespace Tecnickcom\TCPDF\Tests;
use LogicException;
use RuntimeException;
class PdfTools
{
/**
* @var string|null Path to pdfinfo as shell argument
*/
private $pdfinfo = null;
/**
* @var string|null Path to pdftopng as shell argument
*/
private $pdftopng = null;
/**
* @var string|null Path to pdftoppm as shell argument
*/
private $pdftoppm = null;
/**
* @var bool
*/
private $verbose;
/**
* @var string
*/
private $pdfinfoVersionInfo;
/**
* @var string
*/
private $pdftopngVersionInfo;
/**
* @param string[] $tools Path to PDF tool executables (indexed by tool name)
* @param bool $verbose
*/
public function __construct(
array $tools,
$verbose = false
) {
if (!empty($tools['pdfinfo'])) {
$this->pdfinfo = escapeshellarg($tools['pdfinfo']);
}
if (!empty($tools['pdftopng'])) {
$this->pdftopng = escapeshellarg($tools['pdftopng']);
}
if (!empty($tools['pdftoppm'])) {
$this->pdftoppm = escapeshellarg($tools['pdftoppm']);
}
$this->verbose = $verbose;
}
/**
* @return string pdfinfo version information (multiline information)
* @throws LogicException
* @throws RuntimeException
*/
public function getPdfinfoVersionInfo()
{
if (null === $this->pdfinfo) {
throw new LogicException('No path to pdfinfo. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
if (null === $this->pdfinfoVersionInfo) {
$exec = sprintf('%s -v 2>&1', $this->pdfinfo);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode && 99 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
$this->pdfinfoVersionInfo = implode(PHP_EOL, $output);
}
return $this->pdfinfoVersionInfo;
}
/**
* @return string pdftopng or pdftoppm version information (multiline information)
* @throws LogicException
* @throws RuntimeException
*/
public function getPdftopngVersionInfo()
{
$tool = $this->pdftopng ?: $this->pdftoppm;
if (null === $tool) {
throw new LogicException('No path to pdftopng not pdftoppm. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
if (null === $this->pdftopngVersionInfo) {
$exec = sprintf('%s -v 2>&1', $tool);
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if (0 !== $resultCode && 99 !== $resultCode) {
throw new RuntimeException('Execution failed: ' . $exec);
}
$this->pdftopngVersionInfo = implode(PHP_EOL, $output);
}
return $this->pdftopngVersionInfo;
}
/**
* @param string $file Path of file to check
* @return bool
* @throws LogicException
*/
public function isPdf($file)
{
if (null === $this->pdfinfo) {
throw new LogicException('No path to pdfinfo. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
$exec = implode(' ', array(
$this->pdfinfo,
escapeshellarg($file)
));
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if ($this->verbose) {
echo implode(PHP_EOL, $output) . PHP_EOL;
}
return (0 === $resultCode);
}
private function ensureFolder($path)
{
if (file_exists($path) && is_dir($path) && is_writable($path)) {
return;
}
if (!mkdir($path, 0775, true)) {
throw new RuntimeException('Could not create folder: ' . $path);
}
}
/**
* @param string $file The path of the PDF document to convert into PNG
* @param string $pngRoot The root of the generated PNG file names.
* Example: if <code>$pngRoot = '/usr/home/TCPDF/compare_runs/my-root'</code>,
* the generated PNG files will be as follows:
* <ul>
* <li><code>/usr/home/TCPDF/compare_runs/my-root-0000001.png</code>,</li>
* <li><code>/usr/home/TCPDF/compare_runs/my-root-0000002.png</code>,</li>
* <li>...</li>
* </ul>
* @return string[] List of paths for generated PNG (one per page)
* @throws LogicException
*/
public function convertToPng($file, $pngRoot)
{
if ($this->pdftopng) {
$tool = $this->pdftopng;
} elseif ($this->pdftoppm) {
// When using pdftoppm, we specify the `-png` option to get PNG files
$tool = $this->pdftoppm . ' -png';
}
if (!isset($tool)) {
throw new LogicException('No path to pdftopng nor pdftoppm. Provide it to ' . __CLASS__ . ' PHP class constructor.');
}
$this->ensureFolder(dirname($pngRoot));
$exec = implode(' ', array(
$tool,
escapeshellarg($file),
escapeshellarg($pngRoot),
' 2>&1',
));
if ($this->verbose) {
echo $exec . PHP_EOL;
}
exec($exec, $output, $resultCode);
if ($this->verbose) {
echo implode(PHP_EOL, $output) . PHP_EOL;
}
if (0 !== $resultCode) {
throw new RuntimeException(implode(PHP_EOL, $output));
}
$generatedFiles = glob($pngRoot . '*.png');
if (false === $generatedFiles) {
throw new RuntimeException('Could not get the list of generated PNG files.');
}
return $generatedFiles;
}
}