diff --git a/.php_cs b/.php_cs new file mode 100644 index 0000000..0808815 --- /dev/null +++ b/.php_cs @@ -0,0 +1,21 @@ +exclude('migrations') + ->in(__DIR__); + +$config = PhpCsFixer\Config::create() + ->setUsingCache(true) + ->setRules([ + '@PSR2' => true, + 'array_syntax' => [ + 'syntax' => 'short' + ], + 'no_unused_imports' => true, + 'ordered_imports' => true, + 'psr0' => false, + 'trailing_comma_in_multiline_array' => true, + ]) + ->setFinder($finder); + +return $config; diff --git a/.travis.yml b/.travis.yml index d3dd87a..6d5a153 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,12 +33,6 @@ matrix: - php: 5.6 env: - DEPS=lowest - - php: 5.6 - env: - - DEPS=locked - - TEST_COVERAGE=true - - DEPLOY_DOCS="$(if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo -n 'true' ; else echo -n 'false' ; fi)" - - PATH="$HOME/.local/bin:$PATH" - php: 5.6 env: - DEPS=latest @@ -48,12 +42,35 @@ matrix: - php: 7 env: - DEPS=latest - - php: hhvm + - php: 7.1 + env: + - DEPS=lowest + - php: 7.1 + env: + - DEPS=locked + - TEST_COVERAGE=true + - WITH_CS=true + - DEPLOY_DOCS="$(if [[ $TRAVIS_BRANCH == 'master' && $TRAVIS_PULL_REQUEST == 'false' ]]; then echo -n 'true' ; else echo -n 'false' ; fi)" + - PATH="$HOME/.local/bin:$PATH" + - php: 7.1 + env: + - DEPS=latest + - php: nightly + env: + - DEPS=lowest + - php: nightly + env: + - DEPS=latest + - php: hhvm env: - DEPS=lowest - php: hhvm env: - DEPS=latest + allow_failures: + - php: hhvm + - php: nightly + - php: 5.5 notifications: email: andreas@heigl.org @@ -75,6 +92,8 @@ script: - if [[ $TEST_COVERAGE != 'true' ]]; then composer test ; fi - if [[ $CHECK_CS == 'true' ]]; then composer cs-check ; fi - if [[ $DEPLOY_DOCS == "true" && "$TRAVIS_TEST_RESULT" == "0" ]]; then ./docsinstall.sh; composer api; fi + - if [[ "$WITH_CS" == "true" ]]; then vendor/bin/php-cs-fixer fix --verbose --diff --dry-run; fi + after_success: - if [[ $DEPLOY_DOCS == "true" ]]; then echo "Preparing to build and deploy documentation" ; ./.builddocs.sh ; echo "Completed deploying documentation" ; fi diff --git a/README.md b/README.md index cdcc575..f2b81db 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ [![Build Status](https://travis-ci.org/heiglandreas/Org_Heigl_Ghostscript.svg?branch=master)](https://travis-ci.org/heiglandreas/Org_Heigl_Ghostscript) [![Coverage Status](https://coveralls.io/repos/github/heiglandreas/Org_Heigl_Ghostscript/badge.svg?branch=master)](https://coveralls.io/github/heiglandreas/Org_Heigl_Ghostscript?branch=master) +[![Codacy Badge](https://api.codacy.com/project/badge/Grade/6be2e49960764a688d269c043d30216c)](https://www.codacy.com/app/github_70/Org_Heigl_Ghostscript?utm_source=github.com&utm_medium=referral&utm_content=heiglandreas/Org_Heigl_Ghostscript&utm_campaign=Badge_Grade) A PHP-wrapper to the Ghostscript-CLI diff --git a/composer.json b/composer.json index 12d3ec4..def3ef9 100644 --- a/composer.json +++ b/composer.json @@ -20,9 +20,9 @@ } }, "require-dev": { - "phpunit/phpunit": "^4.8||^5.3", + "phpunit/phpunit": "^5.3", "phpdocumentor/phpdocumentor": "^2.9", - "fabpot/php-cs-fixer": "^1.11" + "friendsofphp/php-cs-fixer": "^2.1" }, "scripts" : { "cs-check": "php-cs-fixer --version && php-cs-fixer fix . --level=psr2 -v --diff --dry-run", diff --git a/doc/usage.md b/doc/usage.md index 0c9d139..a61076a 100644 --- a/doc/usage.md +++ b/doc/usage.md @@ -2,6 +2,8 @@ ## Convert a PDF- or Postscript-File to a JPEG +This is the basic way of creating a JPEG from a PDF-File + ``` _device = 'pngalpha'; - } else { + 'pngmono', + ]; + $this->_device = 'pngalpha'; + if (in_array($device, $devices)) { $this -> _device = $device; } diff --git a/src/Ghostscript.php b/src/Ghostscript.php index bb33059..f41c71e 100644 --- a/src/Ghostscript.php +++ b/src/Ghostscript.php @@ -105,20 +105,48 @@ class Ghostscript { /** - * This property contains the path to the Ghostscript-Application + * No Anti-Aliasing * - * This is set when the class is first loaded + * @var int + */ + const ANTIALIASING_NONE = 1; + + /** + * Low Anti-Aliasing * - * @var string PATH + * @var int */ - private static $PATH = null; + const ANTIALIASING_LOW = 2; + + /** + * Medium Anti-Aliasing + * + * @var int + * @deprecated As there is no "Medium" Anti-Aliasing. Only None, low and + * high + */ + const ANTIALIASING_MEDIUM = 2; + + /** + * High Anti-Aliasing + * + * @var int + */ + const ANTIALIASING_HIGH = 4; + + /** + * Store the resolution + * + * @var string $_resolution + */ + protected $resolution = 72; /** * This property stores the file to process. * * @var SplFileInfo $_infile */ - protected $_infile = null; + protected $infile = null; /** * This property stores the output-filename. @@ -129,22 +157,99 @@ class Ghostscript * * @var string $_outfile */ - protected $_outfile = 'output'; + protected $outfile = 'output'; + + /** + * Stores the anti aliasing level + * + * @var int $_graphicsAntiAliasing + */ + protected $graphicsAntiAliasing = 0; + + /** + * Stores the anti aliasing level + * + * @var int $_textAntiAliasing + */ + protected $textAntiAliasing = 0; + + /** + * Store whether to use CIE for color conversion or not + * + * @var boolean $_useCie + */ + protected $useCie = false; + + /** + * Store any default input-profiles + * + * @var array $_defaultProfile + */ + protected $defaultProfile = []; + + /** + * Store the deviceProfile to use for oputput + * + * @var string|null $_deviceProfile + */ + protected $deviceProfile = null; + + /** + * Which box shall be used for rendering? + * + * @var string|null $_useBox + */ + protected $useBox = null; + + /** + * On which page shall we start rendering? + * + * If NULL this will be ignored + * + * @var int $_pageStart + */ + protected $pageStart = null; + + /** + * On which page shall we stop rendering? + * + * If NULL, this will be ignored + * + * @var int $_pageEnd + */ + protected $pageEnd = null; /** * Which MIME-Types are supported * * @var array $supportedMimeTypes */ - private static $supportedMimeTypes = array( + private static $supportedMimeTypes = [ 'application/eps', 'application/pdf', 'application/ps', - ); + ]; - protected $pageStart = null; + /** + * This property contains the path to the Ghostscript-Application + * + * This is set when the class is first loaded + * + * @var string PATH + */ + private static $PATH = null; - protected $pageEnd = null; + /** + * Create a new Instance of the Ghostscript wrapper. + * + * The new Instance will use a jpeg-device as default + * + * @return void + */ + public function __construct() + { + $this->setDevice('png'); + } /** * Set the path to the gs-executable and return it. @@ -169,9 +274,9 @@ public static function setGsPath($path = null) $path = $output[0]; } if ($path) { - Ghostscript::$PATH = $path; + self::$PATH = $path; } - return Ghostscript::$PATH; + return self::$PATH; } /** @@ -181,7 +286,7 @@ public static function setGsPath($path = null) */ public static function getGsPath() { - return Ghostscript::$PATH; + return self::$PATH; } @@ -205,11 +310,11 @@ public function setInputFile($file) $finfo = new \finfo(); $mime = $finfo->file($file->getPathName(), FILEINFO_MIME); $mime = explode(';', $mime); - if (! in_array($mime[0], Ghostscript::$supportedMimeTypes)) { + if (! in_array($mime[0], self::$supportedMimeTypes)) { throw new \InvalidArgumentException('The provided file seems not to be of a supported MIME-Type'); } } - $this -> _infile = $file; + $this -> infile = $file; return $this; } @@ -220,7 +325,7 @@ public function setInputFile($file) */ public function getInputFile() { - return $this -> _infile; + return $this -> infile; } /** @@ -242,7 +347,7 @@ public function setOutputFile($name = 'output') if (0 !== strpos($name, DIRECTORY_SEPARATOR)) { $name = $this -> getBasePath() . DIRECTORY_SEPARATOR . $name; } - $this -> _outfile = $name; + $this -> outfile = $name; } /** @@ -256,10 +361,10 @@ public function setOutputFile($name = 'output') */ public function getOutputFile() { - if (0 !== strpos($this -> _outfile, DIRECTORY_SEPARATOR)) { - return $this -> getBasePath() . DIRECTORY_SEPARATOR . $this -> _outfile; + if (0 !== strpos($this -> outfile, DIRECTORY_SEPARATOR)) { + return $this -> getBasePath() . DIRECTORY_SEPARATOR . $this -> outfile; } - return $this -> _outfile; + return $this -> outfile; } /** @@ -274,8 +379,8 @@ public function getOutputFile() */ public function getBasePath() { - if (null !== $this -> _infile) { - return dirname($this -> _infile); + if (null !== $this -> infile) { + return dirname($this -> infile); } return sys_get_temp_dir(); } @@ -312,7 +417,7 @@ public function getRenderString() if (null === $this -> getInputFile()) { return ''; } - $string = Ghostscript::getGsPath(); + $string = self::getGsPath(); $string .= ' -dSAFER -dQUIET -dNOPLATFONTS -dNOPAUSE -dBATCH'; $string .= ' -sOutputFile="' . $this -> getOutputFile() . '.' . $this -> getDevice() -> getFileEnding() . '"'; $string.= $this -> getDevice() -> getParameterString(); @@ -324,6 +429,29 @@ public function getRenderString() $string .= ' -dGraphicsAlphaBits=' . $this -> getGraphicsAntiAliasing(); } + + if (true === $this -> useCie()) { + $string .= ' -dUseCIEColor'; + } + + // Set the Rendered Box. + $box = $this -> getBox(); + if (null !== $box) { + $string .= ' -dUse' . ucfirst($box) . 'Box'; + } + + // Set files for ColorManagement. + // As of GS 8.71 there should be a different way to do that. + if ($this -> defaultProfile) { + foreach ($this -> defaultProfile as $profile) { + $string .= ' "' . $profile . '"'; + } + } + $deviceProfile = $this -> getDeviceProfile(); + if (false !== $deviceProfile) { + $string .= ' "' . $deviceProfile . '"'; + } + $string .= $this->getPageRangeString(); $string .= ' "' . $this -> getInputFile() . '"'; @@ -354,7 +482,7 @@ public function getPageRangeString() */ public function isGraphicsAntiAliasingSet() { - if (0 < $this -> _graphicsAntiAliasing) { + if (0 < $this -> graphicsAntiAliasing) { return true; } return false; @@ -370,17 +498,12 @@ public function isGraphicsAntiAliasingSet() public function setGraphicsAntiAliasing($level) { if ($level === 0 || $level === 1 || $level === 2 || $level === 4) { - $this -> _graphicsAntiAliasing = $level; + $this -> graphicsAntiAliasing = $level; } return $this; } - /** - * Stores the anti aliasing level - * - * @var int $_graphicsAntiAliasing - */ - protected $_graphicsAntiAliasing = 0; + /** * Get the text-AntiAliasing level @@ -389,7 +512,7 @@ public function setGraphicsAntiAliasing($level) */ public function getGraphicsAntiAliasing() { - return $this -> _graphicsAntiAliasing; + return $this -> graphicsAntiAliasing; } @@ -400,7 +523,7 @@ public function getGraphicsAntiAliasing() */ public function isTextAntiAliasingSet() { - if (0 < $this -> _textAntiAliasing) { + if (0 < $this -> textAntiAliasing) { return true; } return false; @@ -416,18 +539,11 @@ public function isTextAntiAliasingSet() public function setTextAntiAliasing($level) { if ($level === 0 || $level === 1 || $level === 2 || $level === 4) { - $this -> _textAntiAliasing = $level; + $this -> textAntiAliasing = $level; } return $this; } - /** - * Stores the anti aliasing level - * - * @var int $_textAntiAliasing - */ - protected $_textAntiAliasing = 0; - /** * Get the text-AntiAliasing level * @@ -435,14 +551,9 @@ public function setTextAntiAliasing($level) */ public function getTextAntiAliasing() { - return $this -> _textAntiAliasing; + return $this -> textAntiAliasing; } - const ANTIALIASING_NONE = 0; - const ANTIALIASING_LOW = 1; - const ANTIALIASING_MEDIUM = 2; - const ANTIALIASING_HIGH = 4; - /** * Set the resolution for the rendering * @@ -454,21 +565,14 @@ public function getTextAntiAliasing() public function setResolution($horizontal, $vertical = null) { if (null !== $vertical) { - $this -> _resolution = $horizontal . 'x' . $vertical; + $this -> resolution = $horizontal . 'x' . $vertical; } else { - $this -> _resolution = $horizontal; + $this -> resolution = $horizontal; } return $this; } - /** - * Store the resolution - * - * @var string $_resolution - */ - protected $_resolution = 72; - /** * Get the resolution * @@ -476,7 +580,7 @@ public function setResolution($horizontal, $vertical = null) */ public function getResolution() { - return $this -> _resolution; + return $this -> resolution; } /** @@ -492,26 +596,7 @@ public function setDevice($device) $classname = 'Org_Heigl\\Ghostscript\\Device\\' . ucfirst(strtolower($device)); $device = new $classname(); } - $this -> _device = $device; - } - - /** - * Which device shall be used to render the input file - * - * @var Org_Heigl_Ghostscript_Device_Abstract $_device - */ - protected $_device = null; - - /** - * Create a new Instance of the Ghostscript wrapper. - * - * The new Instance will use a jpeg-device as default - * - * @return void - */ - public function __construct() - { - $this->setDevice('png'); + $this -> device = $device; } /** @@ -521,7 +606,7 @@ public function __construct() */ public function getDevice() { - return $this -> _device; + return $this -> device; } /** @@ -533,7 +618,7 @@ public function getDevice() */ public function setUseCie($useCie = true) { - $this -> _useCie = (bool) $useCie; + $this -> useCie = (bool) $useCie; return $this; } @@ -544,12 +629,203 @@ public function setUseCie($useCie = true) */ public function useCie() { - return (bool) $this -> _useCie; + return (bool) $this -> useCie; } + /** + * Which Box shall be used to generate the output from. + * + * This can be one of + * - crop + * - media + * + * @param string $box The box to use + * + * @return Org_Heigl_Ghostscript + */ + public function useBox($box) + { + $box = strtolower($box); + switch ($box) { + case 'crop': + case 'media': + case 'trim': + $this -> useBox = $box; + break; + default: + $this -> useBox = null; + break; + } + return $this; + } + + /** + * Get the name of the box to be used for rendering + * + * This returns either 'crop' or 'media' if one of these boxes shall be + * rendered or NULL if the switch shall not be set. + * + * @return string|null + */ + public function getBox() + { + return $this -> useBox; + } + + /** + * Add the given Profile for Color-Management as Input-Profile. + * + * The Profile will be added as CSA-File to perform the translation of + * Colors from the Input-File to the Internal ProcessColosSpace. + * + * The CSA-File can be created via the OpenSource-Tool icc2ps from the + * littleCMS-Package available at http://www.littlecms.org + * + * The CSA-File can be generated via the following command from any + * icc-file: + * + * icc2ps -i > output.csa + * + * This gerneated CSA-File has to be adapted according to the following + * example: + * + * currentglobal true setglobal + * /DefaultCMYK + * [ /CIEBasedDEFG + * << + * ... + * ... + * >> + * ] /ColorSpace defineresource pop + * setglobal + * + * where the Part in the brackets is the part that is generated from the + * icc2ps-tool. + * + * For more Information on Color-Conversion and Color-Management refer to + * the Homepage of ghostscript, the ICC or have a look at a Search-Engine. + * + * @param string $profile The Name of the CSA-Profile to use or the complete + * path to an appropriate CSA-File. + * @param string $space The Color-Space to set the profile for. This can + * be one of 'rgb', 'cmyk' or 'gray'. This parameter is currently not + * supported! + * + * @see http://www.littlecms.org + * @see http://www.ghostscript.com + * @return Org_Heigl_Ghostscript + */ + public function setDefaultProfile($profile, $space = null) + { + $space = strtolower($space); + if (! in_array($space, [ 'cmyk', 'rgb', 'gray' ])) { + $space = 'cmyk'; + } + if (file_exists($profile)) { + $this -> defaultProfile[$space] = $profile; + } + return $this; + } + + /** + * Get the default Input-Profile + * + * @return string|false + */ + public function getDefaultProfile($space = 'cmyk') + { + if (isset($this -> defaultProfile[$space])) { + return $this -> defautProfile[$space]; + } + return false; + } + + /** + * Add the given Profile for Color-Management as Device-Output-Profile. + * + * The Profile will be added as CRD-File to perform the translation of + * Colors from the Internal ProcessColorSpace to the Output-File. + * + * The CRD-File can be created via the OpenSource-Tool icc2ps from the + * littleCMS-Package available at http://www.littlecms.org + * + * The CRD-File can be generated via the following command from any + * icc-file: + * + * icc2ps -o > output.crd + * + * This gerneated CRD-File has to be adapted by appeding the following + * line to it: + * + * /Current /ColorRendering findresource setcolorrendering + * + * + * For more Information on Color-Conversion and Color-Management refer to + * the Homepage of ghostscript, the ICC or have a look at a Search-Engine. + * + * @param string $profile The Name of the CRD-Profile to use or the complete + * path to an appropriate CRD-File. + * + * @see http://www.littlecms.org + * @see http://www.ghostscript.com + * @return Org_Heigl_Ghostscript + */ + public function setDeviceProfile($profile) + { + if (file_exists($profile)) { + $this -> deviceProfile = $profile; + } + return $this; + } + + /** + * Get the currently set device-Profile + * + * @return string|false + */ + public function getDeviceProfile() + { + if (null === $this -> deviceProfile) { + return false; + } + return $this -> deviceProfile; + } + + /** + * Set the page to start rendering + * + * @param int $page + * + * @return self + */ + public function setPageStart($page) + { + if (null !== $page) { + $page = (int) $page; + } + $this -> pageStart = $page; + return $this; + } + + /** + * Set the page to stop rendering + * + * @param int $page + * + * @return self + */ + public function setPageEnd($page) + { + if (null !== $page) { + $page = (int) $page; + } + $this -> pageEnd = $page; + return $this; + } + /** * Set a page-Range - * + * * @param $startPage * @param $endPage * @@ -565,13 +841,6 @@ public function setPages($startPage, $endPage = null) return $this; } - - /** - * Store whether to use CIE for color conversion or not - * - * @var boolean $_useCie - */ - protected $_useCie = false; } Ghostscript::setGsPath(); diff --git a/tests/GhostscriptTest.php b/tests/GhostscriptTest.php index aa312f3..a2c39bd 100644 --- a/tests/GhostscriptTest.php +++ b/tests/GhostscriptTest.php @@ -138,10 +138,10 @@ public function testTextAntiAliasing() $this -> assertEquals(2, $f -> getTextAntiAliasing()); $f -> setTextAntiAliasing(Ghostscript::ANTIALIASING_LOW); $this -> assertTrue($f -> isTextAntiAliasingSet()); - $this -> assertEquals(1, $f -> getTextAntiAliasing()); + $this -> assertEquals(2, $f -> getTextAntiAliasing()); $f -> setTextAntiAliasing(Ghostscript::ANTIALIASING_NONE); - $this -> assertFalse($f -> isTextAntiAliasingSet()); - $this -> assertEquals(0, $f -> getTextAntiAliasing()); + $this -> assertTrue($f -> isTextAntiAliasingSet()); + $this -> assertEquals(1, $f -> getTextAntiAliasing()); } public function testGraphicsAntiAliasing() @@ -159,11 +159,11 @@ public function testGraphicsAntiAliasing() $this -> assertEquals(2, $f -> getGraphicsAntiAliasing()); $this -> assertTrue($f -> isGraphicsAntiAliasingSet()); $f -> setGraphicsAntiAliasing(Ghostscript::ANTIALIASING_LOW); - $this -> assertEquals(1, $f -> getGraphicsAntiAliasing()); + $this -> assertEquals(2, $f -> getGraphicsAntiAliasing()); $this -> assertTrue($f -> isGraphicsAntiAliasingSet()); $f -> setGraphicsAntiAliasing(Ghostscript::ANTIALIASING_NONE); - $this -> assertEquals(0, $f -> getGraphicsAntiAliasing()); - $this -> assertFalse($f -> isGraphicsAntiAliasingSet()); + $this -> assertEquals(1, $f -> getGraphicsAntiAliasing()); + $this -> assertTrue($f -> isGraphicsAntiAliasingSet()); } public function testRenderingStrings() @@ -183,10 +183,10 @@ public function testRenderingStrings() $expect = $path . ' -dSAFER -dQUIET -dNOPLATFONTS -dNOPAUSE -dBATCH -sOutputFile="' . $dir . 'output.png" -sDEVICE=pngalpha -r72 -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "' .$filename . '"'; $this -> assertEquals($expect, $f -> getRenderString()); $f -> setTextAntiAliasing(Ghostscript::ANTIALIASING_NONE); - $expect = $path . ' -dSAFER -dQUIET -dNOPLATFONTS -dNOPAUSE -dBATCH -sOutputFile="' . $dir . 'output.png" -sDEVICE=pngalpha -r72 -dGraphicsAlphaBits=4 "' .$filename . '"'; + $expect = $path . ' -dSAFER -dQUIET -dNOPLATFONTS -dNOPAUSE -dBATCH -sOutputFile="' . $dir . 'output.png" -sDEVICE=pngalpha -r72 -dTextAlphaBits=1 -dGraphicsAlphaBits=4 "' .$filename . '"'; $this -> assertEquals($expect, $f -> getRenderString()); $f -> setDevice('jpeg'); - $expect = $path . ' -dSAFER -dQUIET -dNOPLATFONTS -dNOPAUSE -dBATCH -sOutputFile="' . $dir . 'output.jpeg" -sDEVICE=jpeg -dJPEGQ=75 -dQFactor=0.75 -r72 -dGraphicsAlphaBits=4 "' .$filename . '"'; + $expect = $path . ' -dSAFER -dQUIET -dNOPLATFONTS -dNOPAUSE -dBATCH -sOutputFile="' . $dir . 'output.jpeg" -sDEVICE=jpeg -dJPEGQ=75 -dQFactor=0.75 -r72 -dTextAlphaBits=1 -dGraphicsAlphaBits=4 "' .$filename . '"'; $this -> assertEquals($expect, $f -> getRenderString()); } @@ -213,7 +213,7 @@ public function testSettingPages() $this->assertAttributeEquals(null, 'pageEnd', $f); $this->assertEquals(' -dFirstPage=2 -dLastPage=2', $f->getPageRangeString()); - $f->setPages(3,4); + $f->setPages(3, 4); $this->assertAttributeEquals(3, 'pageStart', $f); $this->assertAttributeEquals(4, 'pageEnd', $f); $this->assertEquals(' -dFirstPage=3 -dLastPage=4', $f->getPageRangeString());