├── .editorconfig ├── .github ├── dependabot.yaml └── workflows │ └── ci.yaml ├── .gitignore ├── .idea ├── .name ├── Ghostscript.iml ├── composerJson.xml ├── copyright │ └── profiles_settings.xml ├── dictionaries │ └── daniel.xml ├── encodings.xml ├── inspectionProfiles │ ├── Project_Default.xml │ └── profiles_settings.xml ├── modules.xml ├── phing.xml ├── php.xml ├── scopes │ └── scope_settings.xml └── vcs.xml ├── .scrutinizer.yml ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE.md ├── README.md ├── build.xml ├── composer.json ├── phpunit.xml.dist ├── src ├── Device │ ├── AbstractDevice.php │ ├── BoundingBoxInfo.php │ ├── CommandLineParameters │ │ ├── EpsTrait.php │ │ ├── FontTrait.php │ │ ├── IccColorTrait.php │ │ ├── InteractionTrait.php │ │ ├── OtherTrait.php │ │ ├── OutputSelectionTrait.php │ │ ├── PageTrait.php │ │ ├── RenderingTrait.php │ │ └── ResourceTrait.php │ ├── CommandLineParametersTrait.php │ ├── DistillerParameters │ │ ├── AdvancedTrait.php │ │ ├── ColorConversionTrait.php │ │ ├── ColorImageCompressionTrait.php │ │ ├── FontTrait.php │ │ ├── GrayImageCompressionTrait.php │ │ ├── MonoImageCompressionTrait.php │ │ └── PageCompressionTrait.php │ ├── DistillerParametersTrait.php │ ├── Inkcov.php │ ├── NoDisplay.php │ ├── PdfInfo.php │ └── PdfWrite.php ├── Enum │ ├── AutoRotatePages.php │ ├── Binding.php │ ├── CannotEmbedFontPolicy.php │ ├── ColorAndGrayImageFilter.php │ ├── ColorConversionStrategy.php │ ├── DefaultRenderingIntent.php │ ├── ImageDownsampleType.php │ ├── MonoImageFilter.php │ ├── PdfSettings.php │ ├── ProcessColorModel.php │ ├── TransferFunctionInfo.php │ └── UcrAndBgInfo.php ├── Ghostscript.php ├── GhostscriptInterface.php ├── Input.php └── Process │ ├── Argument.php │ └── Arguments.php └── tests ├── data ├── input.pdf └── pdf_info.ps └── src ├── Device ├── AbstractDeviceTest.php ├── BoundingBoxInfoTest.php ├── CommandLineParameters │ ├── FontTraitTest.php │ ├── InteractionTraitTest.php │ ├── OtherTraitTest.php │ └── PageTraitTest.php ├── DeviceTestCase.php ├── DistillerParameters │ ├── AdvancedTraitTest.php │ ├── ColorConversionTraitTest.php │ ├── ColorImageCompressionTraitTest.php │ ├── FontTraitTest.php │ ├── GrayImageCompressionTraitTest.php │ ├── MonoImageCompressionTraitTest.php │ └── PageCompressionTraitTest.php ├── DistillerParametersTraitTest.php ├── InkcovTest.php ├── NoDisplayTest.php ├── PdfInfoTest.php └── PdfWriteTest.php ├── Enum ├── AutoRotatePagesTest.php ├── BindingTest.php ├── CannotEmbedFontPolicyTest.php ├── ColorAndGrayImageFilterTest.php ├── ColorConversionStrategyTest.php ├── DefaultRenderingIntentTest.php ├── ImageDownsampleTypeTest.php ├── MonoImageFilterTest.php ├── PdfSettingsTest.php ├── ProcessColorModelTest.php ├── TransferFunctionInfoTest.php └── UcrAndBgInfoTest.php ├── GhostscriptTest.php ├── InputTest.php └── Process ├── ArgumentTest.php └── ArgumentsTest.php /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Default settings 7 | [*] 8 | end_of_line = lf 9 | indent_size = 4 10 | indent_style = space 11 | insert_final_newline = true 12 | trim_trailing_whitespace = true 13 | 14 | # Markdown file settings 15 | [*.md] 16 | trim_trailing_whitespace = false 17 | 18 | # YAML file settings 19 | [*.yaml] 20 | indent_size = 2 21 | -------------------------------------------------------------------------------- /.github/dependabot.yaml: -------------------------------------------------------------------------------- 1 | version: 2 2 | 3 | updates: 4 | - package-ecosystem: 'composer' 5 | directory: '/' 6 | schedule: 7 | interval: 'weekly' 8 | 9 | - package-ecosystem: 'github-actions' 10 | directory: '/' 11 | schedule: 12 | interval: 'weekly' 13 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | pull_request: 3 | branches: 4 | - master 5 | push: 6 | branches: 7 | - master 8 | 9 | env: 10 | PHP_EXTENSIONS: intl, pcov 11 | PHP_VERSION: 8.3 12 | 13 | jobs: 14 | tests: 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - name: Checkout code 19 | uses: actions/checkout@v4 20 | with: 21 | fetch-depth: 0 22 | 23 | - name: Install packages 24 | uses: awalsh128/cache-apt-pkgs-action@latest 25 | with: 26 | packages: ghostscript 27 | version: 1 28 | 29 | - name: Setup PHP extensions cache 30 | id: php-extensions-cache 31 | uses: shivammathur/cache-extensions@v1 32 | with: 33 | php-version: ${{ env.PHP_VERSION }} 34 | extensions: ${{ env.PHP_EXTENSIONS }} 35 | key: ${{ runner.os }}-PHP-Extensions-V1 36 | 37 | - name: Cache PHP extensions 38 | uses: actions/cache@v4 39 | with: 40 | path: ${{ steps.php-extensions-cache.outputs.dir }} 41 | key: ${{ steps.php-extensions-cache.outputs.key }} 42 | restore-keys: ${{ steps.php-extensions-cache.outputs.key }} 43 | 44 | - name: Setup PHP 45 | uses: shivammathur/setup-php@v2 46 | with: 47 | php-version: ${{ env.PHP_VERSION }} 48 | extensions: ${{ env.PHP_EXTENSIONS }} 49 | 50 | - name: Get Composer cache directory 51 | id: composer-cache 52 | run: echo "dir=$(composer config cache-files-dir)" >> $GITHUB_OUTPUT 53 | 54 | - name: Cache Composer dependencies 55 | uses: actions/cache@v4 56 | with: 57 | path: ${{ steps.composer-cache.outputs.dir }} 58 | key: ${{ runner.os }}-Composer-V1-${{ hashFiles('**/composer.lock') }} 59 | restore-keys: ${{ runner.os }}-Composer-V1- 60 | 61 | - name: Install Composer dependencies 62 | run: composer update --prefer-dist --prefer-stable --no-progress 63 | 64 | - name: Run PHPUnit tests 65 | run: vendor/bin/phpunit --coverage-clover=coverage.clover --coverage-text 66 | 67 | - name: Upload coverage to Scrutinizer 68 | run: vendor/bin/ocular code-coverage:upload --format=php-clover coverage.clover 69 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | build/ 3 | cache/ 4 | vendor/ 5 | .phpunit.cache/ 6 | .phpunit.result.cache 7 | composer.phar 8 | composer.lock 9 | coverage.clover 10 | phpunit.xml 11 | -------------------------------------------------------------------------------- /.idea/.name: -------------------------------------------------------------------------------- 1 | Ghostscript -------------------------------------------------------------------------------- /.idea/Ghostscript.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /.idea/composerJson.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/dictionaries/daniel.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ghostscript 5 | joboptions 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 17 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /.idea/phing.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | $USER_HOME$/.composer/vendor/bin/phing 5 | 6 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/scopes/scope_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.scrutinizer.yml: -------------------------------------------------------------------------------- 1 | filter: 2 | excluded_paths: 3 | - "tests/*" 4 | 5 | checks: 6 | php: 7 | remove_extra_empty_lines: true 8 | remove_php_closing_tag: true 9 | remove_trailing_whitespace: true 10 | fix_use_statements: 11 | remove_unused: true 12 | preserve_multiple: false 13 | preserve_blanklines: true 14 | order_alphabetically: true 15 | fix_php_opening_tag: true 16 | fix_linefeed: true 17 | fix_line_ending: true 18 | fix_identation_4spaces: true 19 | fix_doc_comments: true 20 | 21 | tools: 22 | external_code_coverage: 23 | timeout: 600 24 | runs: 2 25 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All Notable changes to `gravitymedia/ghostscript` will be documented in this file. 4 | This project adheres to [Semantic Versioning](http://semver.org/). 5 | 6 | ## NEXT - YYYY-MM-DD 7 | 8 | ### Added 9 | - Nothing 10 | 11 | ### Changed 12 | - Nothing 13 | 14 | ### Deprecated 15 | - Nothing 16 | 17 | ### Removed 18 | - Nothing 19 | 20 | ### Fixed 21 | - Nothing 22 | 23 | ### Security 24 | - Nothing 25 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/GravityMedia/Ghostscript). 6 | 7 | ## Pull Requests 8 | 9 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 10 | 11 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 12 | 13 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 14 | 15 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 16 | 17 | - **Create feature branches** - Don't ask us to pull from your master branch. 18 | 19 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 20 | 21 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. 22 | 23 | ## Running Tests 24 | 25 | ``` bash 26 | $ php vendor/bin/phpunit --coverage-text --verbose 27 | ``` 28 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Daniel Schröder 4 | 5 | > Permission is hereby granted, free of charge, to any person obtaining a copy 6 | > of this software and associated documentation files (the "Software"), to deal 7 | > in the Software without restriction, including without limitation the rights 8 | > to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | > copies of the Software, and to permit persons to whom the Software is 10 | > furnished to do so, subject to the following conditions: 11 | > 12 | > The above copyright notice and this permission notice shall be included in 13 | > all copies or substantial portions of the Software. 14 | > 15 | > THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | > IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | > FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | > AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | > LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | > OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Ghostscript 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/gravitymedia/ghostscript.svg)](https://packagist.org/packages/gravitymedia/ghostscript) 4 | [![Software License](https://img.shields.io/packagist/l/gravitymedia/ghostscript.svg)](LICENSE.md) 5 | [![Build Status](https://img.shields.io/github/actions/workflow/status/GravityMedia/Ghostscript/ci.yaml)](https://github.com/GravityMedia/Ghostscript/actions/workflows/ci.yaml) 6 | [![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/GravityMedia/Ghostscript.svg)](https://scrutinizer-ci.com/g/GravityMedia/Ghostscript/code-structure) 7 | [![Quality Score](https://img.shields.io/scrutinizer/g/GravityMedia/Ghostscript.svg)](https://scrutinizer-ci.com/g/GravityMedia/Ghostscript) 8 | [![Total Downloads](https://img.shields.io/packagist/dt/gravitymedia/ghostscript.svg)](https://packagist.org/packages/gravitymedia/ghostscript) 9 | 10 | Ghostscript is an object oriented Ghostscript binary wrapper for PHP. 11 | 12 | ## Requirements 13 | 14 | This library has the following requirements: 15 | 16 | - PHP 8.0+ 17 | - Ghostscript 9.00+ 18 | 19 | ## Installation 20 | 21 | Install Composer in your project: 22 | 23 | ```bash 24 | $ curl -s https://getcomposer.org/installer | php 25 | ``` 26 | 27 | Require the package via Composer: 28 | 29 | ```bash 30 | $ php composer.phar require gravitymedia/ghostscript:v2.4 31 | ``` 32 | 33 | ## Usage 34 | 35 | This is a simple usage example how to convert an input PDF to an output PDF. 36 | 37 | ```php 38 | // Initialize autoloader 39 | require_once __DIR__ . '/vendor/autoload.php'; 40 | 41 | // Import classes 42 | use GravityMedia\Ghostscript\Ghostscript; 43 | use Symfony\Component\Process\Process; 44 | 45 | // Define input and output files 46 | $inputFile = '/path/to/input/file.pdf'; 47 | $outputFile = '/path/to/output/file.pdf'; 48 | 49 | // Create Ghostscript object 50 | $ghostscript = new Ghostscript([ 51 | 'quiet' => false 52 | ]); 53 | 54 | // Create and configure the device 55 | $device = $ghostscript->createPdfDevice($outputFile); 56 | $device->setCompatibilityLevel(1.4); 57 | 58 | // Create process 59 | $process = $device->createProcess($inputFile); 60 | 61 | // Print the command line 62 | print '$ ' . $process->getCommandLine() . PHP_EOL; 63 | 64 | // Run process 65 | $process->run(function ($type, $buffer) { 66 | if ($type === Process::ERR) { 67 | throw new \RuntimeException($buffer); 68 | } 69 | 70 | print $buffer; 71 | }); 72 | ``` 73 | 74 | ## Testing 75 | 76 | Clone this repository, install Composer and all dependencies: 77 | 78 | ```bash 79 | $ php composer.phar install 80 | ``` 81 | 82 | Run the test suite: 83 | 84 | ```bash 85 | $ php composer.phar test 86 | ``` 87 | 88 | ## Generating documentation 89 | 90 | Clone this repository, install Composer and all dependencies: 91 | 92 | ```bash 93 | $ php composer.phar install 94 | ``` 95 | 96 | Generate the documentation to the `build/docs` directory: 97 | 98 | ```bash 99 | $ php composer.phar doc 100 | ``` 101 | 102 | ## Contributing 103 | 104 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 105 | 106 | ## Credits 107 | 108 | - [Daniel Schröder](https://github.com/pCoLaSD) 109 | - [All Contributors](../../contributors) 110 | 111 | ## License 112 | 113 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 114 | -------------------------------------------------------------------------------- /build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gravitymedia/ghostscript", 3 | "description": "Ghostscript is an object oriented Ghostscript binary wrapper for PHP.", 4 | "keywords": [ 5 | "gravitymedia", 6 | "ghostscript" 7 | ], 8 | "homepage": "https://github.com/GravityMedia/Ghostscript", 9 | "license": "MIT", 10 | "authors": [ 11 | { 12 | "name": "Daniel Schröder", 13 | "email": "daniel.schroeder@gravitymedia.de", 14 | "homepage": "https://github.com/pCoLaSD", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.0", 20 | "symfony/process": "^5.0|^6.0|^7.0" 21 | }, 22 | "require-dev": { 23 | "phing/phing": "^2.14", 24 | "phpunit/phpunit": "^9.5|^10.0|^11.0", 25 | "scrutinizer/ocular": "^1.3", 26 | "symfony/finder": "^5.0|^6.0|^7.0", 27 | "sebastian/comparator": ">=1.2.3" 28 | }, 29 | "autoload": { 30 | "psr-4": { 31 | "GravityMedia\\Ghostscript\\": "src/" 32 | } 33 | }, 34 | "autoload-dev": { 35 | "psr-4": { 36 | "GravityMedia\\GhostscriptTest\\": "tests/src/" 37 | } 38 | }, 39 | "scripts": { 40 | "test": "php vendor/bin/phing test", 41 | "doc": "php vendor/bin/phing doc" 42 | }, 43 | "extra": { 44 | "branch-alias": { 45 | "dev-master": "2.0-dev" 46 | } 47 | }, 48 | "archive": { 49 | "exclude": [ 50 | "/.*", 51 | "/*.php", 52 | "/build.*", 53 | "/composer.*", 54 | "/phpunit.*", 55 | "/tests" 56 | ] 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | src 27 | 28 | 29 | 30 | 31 | tests/src 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/Device/AbstractDevice.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device; 9 | 10 | use GravityMedia\Ghostscript\Ghostscript; 11 | use GravityMedia\Ghostscript\GhostscriptInterface; 12 | use GravityMedia\Ghostscript\Input; 13 | use GravityMedia\Ghostscript\Process\Argument; 14 | use GravityMedia\Ghostscript\Process\Arguments; 15 | use Symfony\Component\Process\Process; 16 | 17 | /** 18 | * The abstract device class. 19 | * 20 | * @package GravityMedia\Ghostscript\Devices 21 | */ 22 | abstract class AbstractDevice 23 | { 24 | /** 25 | * Use command line options. 26 | */ 27 | use CommandLineParametersTrait; 28 | 29 | /** 30 | * Use rendering parameters. 31 | */ 32 | use CommandLineParameters\RenderingTrait; 33 | 34 | /** 35 | * Use page parameters. 36 | */ 37 | use CommandLineParameters\PageTrait; 38 | 39 | /** 40 | * Use font-related parameters. 41 | */ 42 | use CommandLineParameters\FontTrait; 43 | 44 | /** 45 | * Use resource-related parameters. 46 | */ 47 | use CommandLineParameters\ResourceTrait; 48 | 49 | /** 50 | * Use interaction parameters. 51 | */ 52 | use CommandLineParameters\InteractionTrait; 53 | 54 | /** 55 | * Use device and output selection parameters. 56 | */ 57 | use CommandLineParameters\OutputSelectionTrait; 58 | 59 | /** 60 | * Use EPS parameters. 61 | */ 62 | use CommandLineParameters\EpsTrait; 63 | 64 | /** 65 | * Use ICC color parameters. 66 | */ 67 | use CommandLineParameters\IccColorTrait; 68 | 69 | /** 70 | * Use other parameters. 71 | */ 72 | use CommandLineParameters\OtherTrait; 73 | 74 | /** 75 | * The Ghostscript object. 76 | */ 77 | protected GhostscriptInterface $ghostscript; 78 | 79 | /** 80 | * The arguments object. 81 | */ 82 | private Arguments $arguments; 83 | 84 | /** 85 | * Create abstract device object. 86 | */ 87 | public function __construct(GhostscriptInterface $ghostscript, Arguments $arguments) 88 | { 89 | $this->ghostscript = $ghostscript; 90 | $this->arguments = $arguments; 91 | } 92 | 93 | /** 94 | * Get argument. 95 | * 96 | * @param string $name 97 | * 98 | * @return null|Argument 99 | */ 100 | protected function getArgument($name) 101 | { 102 | return $this->arguments->getArgument($name); 103 | } 104 | 105 | /** 106 | * Whether argument is set. 107 | * 108 | * @param string $name 109 | * 110 | * @return bool 111 | */ 112 | protected function hasArgument($name) 113 | { 114 | return null !== $this->getArgument($name); 115 | } 116 | 117 | /** 118 | * Get argument value. 119 | * 120 | * @param string $name 121 | * 122 | * @return null|string 123 | */ 124 | protected function getArgumentValue($name) 125 | { 126 | $argument = $this->getArgument($name); 127 | if (null === $argument) { 128 | return null; 129 | } 130 | 131 | return $argument->getValue(); 132 | } 133 | 134 | /** 135 | * Set argument. 136 | * 137 | * @param string $argument 138 | * 139 | * @return $this 140 | */ 141 | protected function setArgument($argument) 142 | { 143 | $this->arguments->setArgument($argument); 144 | 145 | return $this; 146 | } 147 | 148 | /** 149 | * Sanitize input. 150 | * 151 | * @param null|string|resource|Input $input 152 | * 153 | * @return Input 154 | */ 155 | protected function sanitizeInput($input) 156 | { 157 | if (null === $input) { 158 | $input = $this->ghostscript->getOption('input', new Input()); 159 | } 160 | 161 | if ($input instanceof Input) { 162 | return $input; 163 | } 164 | 165 | $instance = new Input(); 166 | 167 | if (is_resource($input)) { 168 | return $instance->setProcessInput($input); 169 | } 170 | 171 | if (file_exists($input)) { 172 | return $instance->addFile($input); 173 | } 174 | 175 | return $instance->setPostScriptCode((string)$input); 176 | } 177 | 178 | /** 179 | * Create process arguments. 180 | * 181 | * @param Input $input 182 | * 183 | * @throws \RuntimeException 184 | * 185 | * @return array 186 | */ 187 | protected function createProcessArguments(Input $input) 188 | { 189 | $arguments = array_values($this->arguments->toArray()); 190 | 191 | if (null !== $input->getPostScriptCode()) { 192 | array_push($arguments, '-c', $input->getPostScriptCode()); 193 | } 194 | 195 | if (count($input->getFiles()) > 0) { 196 | array_push($arguments, '-f'); 197 | foreach ($input->getFiles() as $file) { 198 | if (!is_file($file)) { 199 | throw new \RuntimeException('Input file does not exist'); 200 | } 201 | 202 | array_push($arguments, $file); 203 | } 204 | } 205 | 206 | if (null !== $input->getProcessInput()) { 207 | array_push($arguments, '-'); 208 | } 209 | 210 | return $arguments; 211 | } 212 | 213 | /** 214 | * Create process object. 215 | * 216 | * @param null|string|resource|Input $input 217 | * 218 | * @throws \RuntimeException 219 | * 220 | * @return Process 221 | */ 222 | public function createProcess($input = null) 223 | { 224 | $requiredVersion = $this->getRequiredVersion(); 225 | $version = $this->ghostscript->getVersion(); 226 | if (version_compare($requiredVersion, $version) > 0) { 227 | throw new \RuntimeException("Ghostscript version {$requiredVersion} or higher is required"); 228 | } 229 | 230 | $input = $this->sanitizeInput($input); 231 | 232 | $arguments = $this->createProcessArguments($input); 233 | array_unshift( 234 | $arguments, 235 | $this->ghostscript->getOption('bin', Ghostscript::DEFAULT_BINARY) 236 | ); 237 | 238 | return new Process( 239 | $arguments, 240 | $this->ghostscript->getOption('cwd'), 241 | $this->ghostscript->getOption('env', []), 242 | $input->getProcessInput(), 243 | $this->ghostscript->getOption('timeout', 60) 244 | ); 245 | } 246 | 247 | protected function getRequiredVersion(): string 248 | { 249 | return '9.00'; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/Device/BoundingBoxInfo.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device; 9 | 10 | use GravityMedia\Ghostscript\Ghostscript; 11 | use GravityMedia\Ghostscript\GhostscriptInterface; 12 | use GravityMedia\Ghostscript\Process\Arguments; 13 | 14 | /** 15 | * The bounding box info device class. 16 | * 17 | * @link http://ghostscript.com/doc/current/Devices.htm#Bounding_box_output 18 | * 19 | * @package GravityMedia\Ghostscript\Devices 20 | */ 21 | class BoundingBoxInfo extends AbstractDevice 22 | { 23 | /** 24 | * Create bounding box info device object. 25 | * 26 | * @param Ghostscript $ghostscript 27 | * @param Arguments $arguments 28 | */ 29 | public function __construct(GhostscriptInterface $ghostscript, Arguments $arguments) 30 | { 31 | parent::__construct($ghostscript, $arguments->setArgument('-sDEVICE=bbox')); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/EpsTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The EPS parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#EPS_parameters 16 | */ 17 | trait EpsTrait 18 | { 19 | /** 20 | * TODO 21 | * 22 | * -dEPSCrop 23 | * Crop an EPS file to the bounding box. This is useful when converting an EPS file to a bitmap. 24 | * 25 | * -dEPSFitPage 26 | * Resize an EPS file to fit the page. This is useful for shrinking or enlarging an EPS file to fit the paper 27 | * size when printing. 28 | * 29 | * This option is also set by the -dFitPage option. 30 | * 31 | * -dNOEPS 32 | * Prevent special processing of EPS files. This is useful when EPS files have incorrect Document Structuring 33 | * Convention comments. 34 | */ 35 | } 36 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/FontTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The font-related parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#Font_related_parameters 16 | */ 17 | trait FontTrait 18 | { 19 | /** 20 | * Get argument value. 21 | * 22 | * @param string $name 23 | * 24 | * @return null|string 25 | */ 26 | abstract protected function getArgumentValue($name); 27 | 28 | /** 29 | * Set argument. 30 | * 31 | * @param string $argument 32 | * 33 | * @return $this 34 | */ 35 | abstract protected function setArgument($argument); 36 | 37 | /** 38 | * TODO 39 | * 40 | * -dDISKFONTS 41 | * Causes individual character outlines to be loaded from the disk the first time they are encountered. 42 | * (Normally Ghostscript loads all the character outlines when it loads a font.) This may allow loading more 43 | * fonts into memory at the expense of slower rendering. DISKFONTS is effective only if the diskfont feature 44 | * was built into the executable; otherwise it is ignored. 45 | * 46 | * -dLOCALFONTS 47 | * Causes Type 1 fonts to be loaded into the current VM -- normally local VM -- instead of always being loaded 48 | * into global VM. Useful only for compatibility with Adobe printers for loading some obsolete fonts. 49 | * 50 | * -dNOCCFONTS 51 | * Suppresses the use of fonts precompiled into the Ghostscript executable. See "Precompiling fonts" in the 52 | * documentation on fonts for details. This is probably useful only for debugging. 53 | * 54 | * -dNOFONTMAP 55 | * Suppresses the normal loading of the Fontmap file. This may be useful in environments without a file system. 56 | * 57 | * -dNOFONTPATH 58 | * Suppresses consultation of GS_FONTPATH. This may be useful for debugging. 59 | * 60 | * -dNOPLATFONTS 61 | * Disables the use of fonts supplied by the underlying platform (X Windows or Microsoft Windows). This may be 62 | * needed if the platform fonts look undesirably different from the scalable fonts. 63 | * 64 | * -dNONATIVEFONTMAP 65 | * Disables the use of font map and corresponding fonts supplied by the underlying platform. This may be needed 66 | * to ensure consistent rendering on the platforms with different fonts, for instance, during regression 67 | * testing. 68 | * 69 | * -sFONTMAP=filename1;filename2;... 70 | * Specifies alternate name or names for the Fontmap file. Note that the names are separated by ":" on Unix 71 | * systems, by ";" on MS Windows systems, and by "," on VMS systems, just as for search paths. 72 | */ 73 | 74 | /** 75 | * Get FONTPATH parameter value 76 | * 77 | * @return string|null 78 | */ 79 | public function getFontPath() 80 | { 81 | return $this->getArgumentValue('-sFONTPATH'); 82 | } 83 | 84 | /** 85 | * Set FONTPATH parameter 86 | * 87 | * @param string $fontPath Specifies a list of directories that will be scanned when looking for fonts not found on 88 | * the search path, overriding the environment variable GS_FONTPATH. 89 | * 90 | * @return $this 91 | */ 92 | public function setFontPath($fontPath) 93 | { 94 | $this->setArgument(sprintf('-sFONTPATH=%s', $fontPath)); 95 | 96 | return $this; 97 | } 98 | 99 | /** 100 | * TODO 101 | * 102 | * -sSUBSTFONT=fontname 103 | * Causes the given font to be substituted for all unknown fonts, instead of using the normal intelligent 104 | * substitution algorithm. Also, in this case, the font returned by findfont is the actual font named fontname, 105 | * not a copy of the font with its FontName changed to the requested one. THIS OPTION SHOULD NOT BE USED WITH 106 | * HIGH LEVEL DEVICES, such as pdfwrite, because it prevents such devices from providing the original font 107 | * names in the output document. The font specified (fontname) will be embedded instead, limiting all future 108 | * users of the document to the same approximate rendering. 109 | * 110 | * -dOLDCFF 111 | * Reverts to using the old, sequential, PostScript CFF parser. New CFF parser is coded in C and uses direct 112 | * access to the font data. This option and the old parser will be removed when the new parser proves its 113 | * reliability. 114 | */ 115 | } 116 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/InteractionTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The interaction-related parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#Interaction_related_parameters 16 | */ 17 | trait InteractionTrait 18 | { 19 | /** 20 | * Whether argument is set 21 | * 22 | * @param string $name 23 | * 24 | * @return bool 25 | */ 26 | abstract protected function hasArgument($name); 27 | 28 | /** 29 | * Get argument value 30 | * 31 | * @param string $name 32 | * 33 | * @return null|string 34 | */ 35 | abstract protected function getArgumentValue($name); 36 | 37 | /** 38 | * Set argument 39 | * 40 | * @param string $argument 41 | * 42 | * @return $this 43 | */ 44 | abstract protected function setArgument($argument); 45 | 46 | /** 47 | * Whether BATCH flag is set 48 | * 49 | * @return bool 50 | */ 51 | public function isBatch() 52 | { 53 | return $this->hasArgument('-dBATCH'); 54 | } 55 | 56 | /** 57 | * Set BATCH flag 58 | * 59 | * Causes Ghostscript to exit after processing all files named on the command line, rather than going into an 60 | * interactive loop reading PostScript commands. Equivalent to putting -c quit at the end of the command line. 61 | * 62 | * @return $this 63 | */ 64 | public function setBatch() 65 | { 66 | $this->setArgument('-dBATCH'); 67 | 68 | return $this; 69 | } 70 | 71 | /** 72 | * Whether NOPAGEPROMPT flag is set 73 | * 74 | * @return bool 75 | */ 76 | public function isNoPagePrompt() 77 | { 78 | return $this->hasArgument('-dNOPAGEPROMPT'); 79 | } 80 | 81 | /** 82 | * Set NOPAGEPROMPT flag 83 | * 84 | * Disables only the prompt, but not the pause, at the end of each page. This may be useful on PC displays that get 85 | * confused if a program attempts to write text to the console while the display is in a graphics mode. 86 | * 87 | * @return $this 88 | */ 89 | public function setNoPagePrompt() 90 | { 91 | $this->setArgument('-dNOPAGEPROMPT'); 92 | 93 | return $this; 94 | } 95 | 96 | /** 97 | * Whether NOPAUSE flag is set 98 | * 99 | * @return bool 100 | */ 101 | public function isNoPause() 102 | { 103 | return $this->hasArgument('-dNOPAUSE'); 104 | } 105 | 106 | /** 107 | * Set NOPAUSE flag 108 | * 109 | * Disables the prompt and pause at the end of each page. Normally one should use this (along with -dBATCH) when 110 | * producing output on a printer or to a file; it also may be desirable for applications where another program is 111 | * "driving" Ghostscript. 112 | * 113 | * @return $this 114 | */ 115 | public function setNoPause() 116 | { 117 | $this->setArgument('-dNOPAUSE'); 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Whether NOPROMPT flag is set 124 | * 125 | * @return bool 126 | */ 127 | public function isNoPrompt() 128 | { 129 | return $this->hasArgument('-dNOPROMPT'); 130 | } 131 | 132 | /** 133 | * Set NOPROMPT flag 134 | * 135 | * Disables the prompt printed by Ghostscript when it expects interactive input, as well as the end-of-page prompt 136 | * (-dNOPAGEPROMPT). This allows piping input directly into Ghostscript, as long as the data doesn't refer to 137 | * currentfile. 138 | * 139 | * @return $this 140 | */ 141 | public function setNoPrompt() 142 | { 143 | $this->setArgument('-dNOPROMPT'); 144 | 145 | return $this; 146 | } 147 | 148 | /** 149 | * Whether QUIET flag is set 150 | * 151 | * @return bool 152 | */ 153 | public function isQuiet() 154 | { 155 | return $this->hasArgument('-dQUIET'); 156 | } 157 | 158 | /** 159 | * Set QUIET flag 160 | * 161 | * Suppresses routine information comments on standard output. This is currently necessary when redirecting device 162 | * output to standard output. 163 | * 164 | * @return $this 165 | */ 166 | public function setQuiet() 167 | { 168 | $this->setArgument('-dQUIET'); 169 | 170 | return $this; 171 | } 172 | 173 | /** 174 | * Whether SHORTERRORS flag is set 175 | * 176 | * @return bool 177 | */ 178 | public function isShortErrors() 179 | { 180 | return $this->hasArgument('-dSHORTERRORS'); 181 | } 182 | 183 | /** 184 | * Set SHORTERRORS flag 185 | * 186 | * Makes certain error and information messages more Adobe-compatible. 187 | * 188 | * @return $this 189 | */ 190 | public function setShortErrors() 191 | { 192 | $this->setArgument('-dSHORTERRORS'); 193 | 194 | return $this; 195 | } 196 | 197 | /** 198 | * Get value of stdout parameter if set 199 | * 200 | * @return string|null 201 | */ 202 | public function getStdout() 203 | { 204 | return $this->getArgumentValue('-sstdout'); 205 | } 206 | 207 | /** 208 | * Set stdout parameter 209 | * 210 | * Redirect PostScript %stdout to a file or stderr, to avoid it being mixed with device stdout. To redirect stdout 211 | * to stderr use -sstdout=%stderr. To cancel redirection of stdout use -sstdout=%stdout or -sstdout=-. 212 | * 213 | * Note that this redirects PostScript output to %stdout but does not change the destination FILE of device output 214 | * as with -sOutputFile=- or even -sOutputFile=%stdout since devices write directly using the stdout FILE * pointer 215 | * with C function calls such as fwrite or fputs. 216 | * 217 | * @param string $filename file to redirect PostScript %stdout to 218 | * 219 | * @return $this 220 | */ 221 | public function setStdout($filename) 222 | { 223 | $this->setArgument(sprintf('-sstdout=%s', $filename)); 224 | 225 | return $this; 226 | } 227 | 228 | /** 229 | * Whether TTYPAUSE flag is set 230 | * 231 | * @return bool 232 | */ 233 | public function isTtyPause() 234 | { 235 | return $this->hasArgument('-dTTYPAUSE'); 236 | } 237 | 238 | /** 239 | * Set TTYPAUSE flag 240 | * 241 | * Causes Ghostscript to read a character from /dev/tty, rather than standard input, at the end of each page. This 242 | * may be useful if input is coming from a pipe. Note that -dTTYPAUSE overrides -dNOPAUSE. Also note that -dTTYPAUSE 243 | * requires opening the terminal device directly, and may cause problems in combination with -dSAFER. Permission 244 | * errors can be avoided by adding the device to the permitted reading list before invoking safer mode. For example: 245 | * gs -dTTYPAUSE -dDELAYSAFER -c '<< /PermitFileReading [ (/dev/tty)] >> setuserparams .locksafe' -dSAFER 246 | * 247 | * @return $this 248 | */ 249 | public function setTtyPause() 250 | { 251 | $this->setArgument('-dTTYPAUSE'); 252 | 253 | return $this; 254 | } 255 | } 256 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/OutputSelectionTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The device and output selection parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#Output_selection_parameters 16 | */ 17 | trait OutputSelectionTrait 18 | { 19 | /** 20 | * TODO 21 | * 22 | * -dNODISPLAY 23 | * Initializes Ghostscript with a null device (a device that discards the output image) rather than the default 24 | * device or the device selected with -sDEVICE=. This is usually useful only when running PostScript code whose 25 | * purpose is to compute something rather than to produce an output image. 26 | * 27 | * -sDEVICE=device 28 | * Selects an alternate initial output device. 29 | * 30 | * -sOutputFile=filename 31 | * Selects an alternate output file (or pipe) for the initial output device, as described above. 32 | * 33 | * -d.IgnoreNumCopies=true 34 | * Some devices implement support for "printing" multiple copies of the input document and some do not, usually 35 | * based on whether it makes sense for a particular output format. This switch instructs all devices to ignore 36 | * a request to print multiple copies, giving more consistent behaviour. 37 | */ 38 | } 39 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/PageTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The page parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#Page_parameters 16 | */ 17 | trait PageTrait 18 | { 19 | /** 20 | * Get argument value. 21 | * 22 | * @param string $name 23 | * 24 | * @return null|string 25 | */ 26 | abstract protected function getArgumentValue($name); 27 | 28 | /** 29 | * Set argument. 30 | * 31 | * @param string $argument 32 | * 33 | * @return $this 34 | */ 35 | abstract protected function setArgument($argument); 36 | 37 | /** 38 | * Get FirstPage parameter value 39 | * 40 | * @return string|null 41 | */ 42 | public function getFirstPage() 43 | { 44 | return $this->getArgumentValue('-dFirstPage'); 45 | } 46 | 47 | /** 48 | * Set FirstPage parameter 49 | * Begins processing on the designated page of the document. 50 | * 51 | * @param int $firstPage. 52 | * 53 | * @return $this 54 | */ 55 | public function setFirstPage($firstPage) 56 | { 57 | $this->setArgument(sprintf('-dFirstPage=%d', $firstPage)); 58 | 59 | return $this; 60 | } 61 | 62 | /** 63 | * Get LastPage parameter value 64 | * 65 | * @return string|null 66 | */ 67 | public function getLastPage() 68 | { 69 | return $this->getArgumentValue('-dLastPage'); 70 | } 71 | 72 | /** 73 | * Set LastPage parameter 74 | * Stops processing after the designated page of the document. 75 | * 76 | * @param int $lastPage. 77 | * 78 | * @return $this 79 | */ 80 | public function setLastPage($lastPage) 81 | { 82 | $this->setArgument(sprintf('-dLastPage=%d', $lastPage)); 83 | 84 | return $this; 85 | } 86 | 87 | /** 88 | * -dFIXEDMEDIA 89 | * Causes the media size to be fixed after initialization, forcing pages of other sizes or orientations to be 90 | * clipped. This may be useful when printing documents on a printer that can handle their requested paper size 91 | * but whose default is some other size. Note that -g automatically sets -dFIXEDMEDIA, but -sPAPERSIZE= does 92 | * not. 93 | * 94 | * @return $this 95 | */ 96 | public function setFixedMedia() 97 | { 98 | $this->setArgument('-dFIXEDMEDIA'); 99 | 100 | return $this; 101 | } 102 | 103 | public function getFixedMedia() 104 | { 105 | return $this->getArgumentValue('-dFIXEDMEDIA'); 106 | } 107 | 108 | /** 109 | * The PDF file will be scaled to fit the current device page size (usually the default page size). 110 | * This is useful for creating fixed size images of PDF files that may have a variety of page sizes, 111 | * for example thumbnail images. 112 | * 113 | * @return $this 114 | */ 115 | public function setPDFFitPage() 116 | { 117 | $this->setArgument('-dPDFFitPage'); 118 | 119 | return $this; 120 | } 121 | 122 | public function getPDFFitPage() 123 | { 124 | return $this->getArgumentValue('-dPDFFitPage'); 125 | } 126 | 127 | /** 128 | * TODO 129 | * 130 | * -dFIXEDRESOLUTION 131 | * Causes the media resolution to be fixed similarly. -r automatically sets -dFIXEDRESOLUTION. 132 | * 133 | * -dPSFitPage 134 | * The page size from the PostScript file setpagedevice operator, or one of the older statusdict page size 135 | * operators (such as letter or a4) will be rotated, scaled and centered on the "best fit" page size from those 136 | * availiable in the InputAttributes list. The -dPSFitPage is most easily used to fit pages when used with the 137 | * -dFIXEDMEDIA option. 138 | * 139 | * This option is also set by the -dFitPage option. 140 | * 141 | * -dORIENT1=true 142 | * -dORIENT1=false 143 | * Defines the meaning of the 0 and 1 orientation values for the setpage[params] compatibility operators. The 144 | * default value of ORIENT1 is true (set in gs_init.ps), which is the correct value for most files that use 145 | * setpage[params] at all, namely, files produced by badly designed applications that "know" that the output 146 | * will be printed on certain roll-media printers: these applications use 0 to mean landscape and 1 to mean 147 | * portrait. -dORIENT1=false declares that 0 means portrait and 1 means landscape, which is the convention used 148 | * by a smaller number of files produced by properly written applications. 149 | * 150 | * -dDEVICEWIDTHPOINTS=w 151 | * -dDEVICEHEIGHTPOINTS=h 152 | * Sets the initial page width to w or initial page height to h respectively, specified in 1/72" units. 153 | * 154 | * -sDEFAULTPAPERSIZE=a4 155 | * This value will be used to replace the device default papersize ONLY if the default papersize for the device 156 | * is 'letter' or 'a4' serving to insulate users of A4 or 8.5x11 from particular device defaults (the 157 | * collection of contributed drivers in Ghostscript vary as to the default size). 158 | * 159 | * -dFitPage 160 | * This is a "convenience" operator that sets the various options to perform page fitting for specific file 161 | * types. 162 | * 163 | * This option sets the -dEPSFitPage, -dPDFFitPage, and the -dFitPage options. 164 | */ 165 | } 166 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/RenderingTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The rendering parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#Rendering_parameters 16 | */ 17 | trait RenderingTrait 18 | { 19 | /** 20 | * TODO 21 | * 22 | * -dCOLORSCREEN 23 | * -dCOLORSCREEN=0 24 | * -dCOLORSCREEN=false 25 | * On high-resolution devices (at least 150 dpi resolution, or -dDITHERPPI specified), -dCOLORSCREEN forces the 26 | * use of separate halftone screens with different angles for CMYK or RGB if halftones are needed (this 27 | * produces the best-quality output); -dCOLORSCREEN=0 uses separate screens with the same frequency and angle; 28 | * -dCOLORSCREEN=false forces the use of a single binary screen. The default if COLORSCREEN is not specified is 29 | * to use separate screens with different angles if the device has fewer than 5 bits per color, and a single 30 | * binary screen (which is never actually used under normal circumstances) on all other devices. 31 | * 32 | * -dDITHERPPI=lpi 33 | * Forces all devices to be considered high-resolution, and forces use of a halftone screen or screens with lpi 34 | * lines per inch, disregarding the actual device resolution. Reasonable values for lpi are N/5 to N/20, where 35 | * N is the resolution in dots per inch. 36 | * 37 | * -dDOINTERPOLATE 38 | * Turns on image interpolation for all images, improving image quality for scaled images at the expense of 39 | * speed. Note that -dNOINTERPOLATE overrides -dDOINTERPOLATE if both are specified. 40 | * 41 | * -dNOINTERPOLATE does nearest neighbour scaling (Bresenham's line algorithm through the image, plotting the 42 | * closest texture coord at each pixel). If we are downscaling this results in some source pixels not appearing 43 | * at all in the destination. If we are upscaling, at least some source pixels cover more than one destination 44 | * pixel. 45 | * 46 | * In all but special cases -dDOINTERPOLATE uses a Mitchell filter function to scale the contributions for each 47 | * output pixel; upscaling, every output pixel ends up being the weighted sum of 16 input pixels, downscaling 48 | * more. Every source pixel has an effect on the output pixels. 49 | * 50 | * Computationally, -dDOINTERPOLATE is much heavier work than -dNOINTERPOLATE (lots of floating point muliplies 51 | * and adds for every output pixel vs simple integer additions, subtractions, and shifts). 52 | * 53 | * The exact algorithm used is from Graphics Gems 3, Chapter I.2 General Filtered Image Rescaling. 54 | * 55 | * -dTextAlphaBits=n 56 | * -dGraphicsAlphaBits=n 57 | * These options control the use of subsample antialiasing. Their use is highly recommended for producing high 58 | * quality rasterizations. The subsampling box size n should be 4 for optimum output, but smaller values can be 59 | * used for faster rendering. Antialiasing is enabled separately for text and graphics content. Allowed values 60 | * are 1, 2 or 4. 61 | * 62 | * Note that because of the way antialiasing blends the edges of shapes into the background when they are drawn 63 | * some files that rely on joining separate filled polygons together to cover an area may not render as 64 | * expected with GraphicsAlphaBits at 2 or 4. If you encounter strange lines within solid areas, try rendering 65 | * that file again with -dGraphicsAlphaBits=1. 66 | * 67 | * -dAlignToPixels=n 68 | * Chooses glyph alignent to integral pixel boundaries (if set to the value 1) or to subpixels (value 0). 69 | * Subpixels are a smaller raster grid which is used internally for text antialiasing. The number of subpixels 70 | * in a pixel usually is 2^TextAlphaBits, but this may be automatically reduced for big characters to save 71 | * space in character cache. 72 | * 73 | * The parameter has no effect if -dTextAlphaBits=1. Default value is 0. 74 | * 75 | * Setting -dAlignToPixels=0 can improve rendering of poorly hinted fonts, but may impair the appearance of 76 | * well-hinted fonts. 77 | * 78 | * -dGridFitTT=n 79 | * This specifies the initial value for the implementation specific user parameter GridFitTT. It controls grid 80 | * fitting of True Type fonts (Sometimes referred to as "hinting", but strictly speaking the latter is a 81 | * feature of Type 1 fonts). Setting this to 2 enables automatic grid fitting for True Type glyphs. The value 0 82 | * disables grid fitting. The default value is 2. For more information see the description of the user 83 | * parameter GridFitTT. 84 | * 85 | * -dUseCIEColor 86 | * Set UseCIEColor in the page device dictionary, remapping device-dependent color values through a Postscript 87 | * defined CIE color space. Document DeviceGray, DeviceRGB and DeviceCMYK source colors will be substituted 88 | * respectively by Postscript CIEA, CIEABC and CIEDEFG color spaces. See the document GS9 Color Management for 89 | * details on how this option will interact with Ghostscript's ICC-based color workflow. If accurate colors are 90 | * desired, it is recommended that an ICC workflow be used. 91 | * 92 | * -dNOCIE 93 | * Substitutes DeviceGray for CIEBasedA, DeviceRGB for CIEBasedABC and CIEBasedDEF spaces and DeviceCMYK fpr 94 | * CIEBasedDEFG color spaces. Useful only on very slow systems where color accuracy is less important. 95 | * 96 | * -dNOSUBSTDEVICECOLORS 97 | * This switch prevents the substitution of the ColorSpace resources (DefaultGray, DefaultRGB, and DefaultCMYK) 98 | * for the DeviceGray, DeviceRGB, and DeviceCMYK color spaces. This switch is primarily useful for PDF creation 99 | * using the pdfwrite device when retaining the color spaces from the original document is important. 100 | * 101 | * -dNOPSICC 102 | * Disables the automatic loading and use of an input color space that is contained in a PostScript file as DSC 103 | * comments starting with the %%BeginICCProfile: comment. ICC profiles are sometimes embedded by applications 104 | * to convey the exact input color space allowing better color fidelity. Since the embedded ICC profiles often 105 | * use multidimensional RenderTables, color conversion may be slower than using the Default color conversion 106 | * invoked when the -dUseCIEColor option is specified, therefore the -dNOPSICC option may result in improved 107 | * performance at slightly reduced color fidelity. 108 | * 109 | * -dNOINTERPOLATE 110 | * Turns off image interpolation, improving performance on interpolated images at the expense of image quality. 111 | * -dNOINTERPOLATE overrides -dDOINTERPOLATE. 112 | * 113 | * -dNOTRANSPARENCY 114 | * Turns off PDF 1.4 transparency, resulting in faster (but possibly incorrect) rendering of pages containing 115 | * PDF 1.4 transparency and blending. 116 | * 117 | * -dNO_TN5044 118 | * Turns off the TN 5044 psuedo operators. These psuedo operators are not a part of the official Postscript 119 | * specification. However they are defined in Technical Note #5044 Color Separation Conventions for PostScript 120 | * Language Programs. These psuedo operators are required for some files from QuarkXPress. However some files 121 | * from Corel 9 and Illustrator 88 do not operate properly if these operators are present. 122 | * 123 | * -dDOPS 124 | * Enables processing of DoPS directives in PDF files. DoPS has in fact been deprecated for some time. Use of 125 | * this option is not recommended in security-conscious applications, as it increases the scope for malicious 126 | * code. -dDOPS has no effect on processing of PostScript source files. Note: in releases 7.30 and earlier, 127 | * processing of DoPS was always enabled. 128 | */ 129 | } 130 | -------------------------------------------------------------------------------- /src/Device/CommandLineParameters/ResourceTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\CommandLineParameters; 9 | 10 | /** 11 | * The resource-related parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\CommandLineParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#Resource_related_parameters 16 | */ 17 | trait ResourceTrait 18 | { 19 | /** 20 | * TODO 21 | * 22 | * -sGenericResourceDir=path 23 | * Specifies a path to resource files. The value is platform dependent. It must end with a directory separator. 24 | * 25 | * A note for Windows users, Artifex recommends the use of the forward slash delimiter due to the special 26 | * interpretation of \" by the Microsoft C startup code. See Parsing C Command-Line Arguments for more 27 | * information. 28 | * 29 | * Adobe specifies GenericResourceDir to be an absolute path to a single resource directory. Ghostscript 30 | * instead maintains multiple resource directories and uses an extended method for finding resources, which is 31 | * explained in "Finding PostScript Level 2 resources". 32 | * 33 | * Due to the extended search method, Ghostscript uses GenericResourceDir only as a default directory for 34 | * resources being not installed. Therefore GenericResourceDir may be considered as a place where new resources 35 | * to be installed. The default implementation of the function ResourceFileName uses GenericResourceDir when 36 | * (1) it is an absolute path, or (2) the resource file is absent. The extended search method does not call 37 | * ResourceFileName . 38 | * 39 | * Default value is (./Resource/) for Unix, and an equivalent one on other platforms. 40 | * 41 | * -sFontResourceDir=path 42 | * Specifies a path where font files are installed. It's meaning is similar to GenericResourceDir. 43 | * 44 | * Default value is (./Font/) for Unix, and an equivalent one on other platforms. 45 | */ 46 | } 47 | -------------------------------------------------------------------------------- /src/Device/CommandLineParametersTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device; 9 | 10 | /** 11 | * The general Ghostscript command line parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript 14 | * 15 | * @link http://ghostscript.com/doc/current/Use.htm#General_switches 16 | */ 17 | trait CommandLineParametersTrait 18 | { 19 | /** 20 | * TODO 21 | * 22 | * Input control 23 | * 24 | * @filename 25 | * Causes Ghostscript to read filename and treat its contents the same as the command line. (This was intended 26 | * primarily for getting around DOS's 128-character limit on the length of a command line.) Switches or file 27 | * names in the file may be separated by any amount of white space (space, tab, line break); there is no limit 28 | * on the size of the file. 29 | * 30 | * -- filename arg1 ... 31 | * -+ filename arg1 ... 32 | * Takes the next argument as a file name as usual, but takes all remaining arguments (even if they have the 33 | * syntactic form of switches) and defines the name ARGUMENTS in userdict (not systemdict) as an array of those 34 | * strings, before running the file. When Ghostscript finishes executing the file, it exits back to the shell. 35 | * 36 | * -@ filename arg1 ... 37 | * Does the same thing as -- and -+, but expands @filename arguments. 38 | * 39 | * - 40 | * -_ 41 | * These are not really switches: they tell Ghostscript to read from standard input, which is coming from a 42 | * file 43 | * or a pipe, with or without buffering. On some systems, Ghostscript may read the input one character at a 44 | * time, which is useful for programs such as ghostview that generate input for Ghostscript dynamically and 45 | * watch for some response, but can slow processing. If performance is significantly slower than with a named 46 | * file, try '-_' which always reads the input in blocks. However, '-' is equivalent on most systems. 47 | * 48 | * -c token ... 49 | * -c string ... 50 | * Interprets arguments as PostScript code up to the next argument that begins with "-" followed by a 51 | * non-digit, 52 | * or with "@". For example, if the file quit.ps contains just the word "quit", then -c quit on the command 53 | * line 54 | * is equivalent to quit.ps there. Each argument must be valid PostScript, either individual tokens as defined 55 | * by the token operator, or a string containing valid PostScript. 56 | * 57 | * -f 58 | * Interprets following non-switch arguments as file names to be executed using the normal run command. Since 59 | * this is the default behavior, -f is useful only for terminating the list of tokens for the -c switch. 60 | * 61 | * -ffilename 62 | * Execute the given file, even if its name begins with a "-" or "@". 63 | * 64 | * File searching 65 | * 66 | * Note that by "library files" here we mean all the files identified using the search rule under "How Ghostscript 67 | * finds files" above: Ghostscript's own initialization files, fonts, and files named on the command line. 68 | * 69 | * -Idirectories 70 | * -I directories 71 | * Adds the designated list of directories at the head of the search path for library files. 72 | * 73 | * -P 74 | * Makes Ghostscript look first in the current directory for library files. 75 | * 76 | * -P- 77 | * Makes Ghostscript not look first in the current directory for library files (unless, of course, the first 78 | * explicitly supplied directory is "."). This is now the default. 79 | * 80 | * Setting parameters 81 | * 82 | * -Dname 83 | * -dname 84 | * Define a name in systemdict with value=true. 85 | * 86 | * -Dname=token 87 | * -dname=token 88 | * Define a name in systemdict with the given value. The value must be a valid PostScript token (as defined by 89 | * the token operator). If the token is a non-literal name, it must be true, false, or null. It is recommeded 90 | * that this is used only for simple values -- use -c (above) for complex values such as procedures, arrays or 91 | * dictionaries. Note that these values are defined before other names in systemdict, so any name that that 92 | * conflicts with one usually in systemdict will be replaced by the normal definition during the interpreter 93 | * initialization. 94 | * 95 | * -Sname=string 96 | * -sname=string 97 | * Define a name in systemdict with a given string as value. This is different from -d. For example, -dXYZ=35 98 | * on 99 | * the command line is equivalent to the program fragment 100 | * 101 | * /XYZ 35 def 102 | * 103 | * whereas -sXYZ=35 is equivalent to 104 | * 105 | * /XYZ (35) def 106 | * 107 | * -uname 108 | * Un-define a name, cancelling -d or -s. 109 | * 110 | * Note that the initialization file gs_init.ps makes systemdict read-only, so the values of names defined with -D, 111 | * -d, -S, and -s cannot be changed -- although, of course, they can be superseded by definitions in userdict or 112 | * other dictionaries. However, device parameters set this way (PageSize, Margins, etc.) are not read-only, and can 113 | * be changed by code in PostScript files. 114 | * 115 | * -gnumber1xnumber2 116 | * Equivalent to -dDEVICEWIDTH=number1 and -dDEVICEHEIGHT=number2, specifying the device width and height in 117 | * pixels for the benefit of devices such as X11 windows and VESA displays that require (or allow) you to 118 | * specify width and height. Note that this causes documents of other sizes to be clipped, not scaled: see 119 | * -dFIXEDMEDIA below. 120 | * 121 | * -rnumber (same as -rnumberxnumber) 122 | * -rnumber1xnumber2 123 | * Equivalent to -dDEVICEXRESOLUTION=number1 and -dDEVICEYRESOLUTION=number2, specifying the device horizontal 124 | * and vertical resolution in pixels per inch for the benefit of devices such as printers that support multiple 125 | * X and Y resolutions. 126 | */ 127 | } 128 | -------------------------------------------------------------------------------- /src/Device/DistillerParameters/FontTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\DistillerParameters; 9 | 10 | use GravityMedia\Ghostscript\Enum\CannotEmbedFontPolicy; 11 | use GravityMedia\Ghostscript\Enum\PdfSettings; 12 | 13 | /** 14 | * The font distiller parameters trait. 15 | * 16 | * @package GravityMedia\Ghostscript\Device\DistillerParameters 17 | * 18 | * @link http://ghostscript.com/doc/current/Ps2pdf.htm 19 | */ 20 | trait FontTrait 21 | { 22 | /** 23 | * Get argument value 24 | * 25 | * @param string $name 26 | * 27 | * @return null|string 28 | */ 29 | abstract protected function getArgumentValue($name); 30 | 31 | /** 32 | * Set argument 33 | * 34 | * @param string $argument 35 | * 36 | * @return $this 37 | */ 38 | abstract protected function setArgument($argument); 39 | 40 | /** 41 | * Get PDF settings 42 | * 43 | * @return string 44 | */ 45 | abstract public function getPdfSettings(); 46 | 47 | /** 48 | * Get cannot embed font policy 49 | * 50 | * @return string 51 | */ 52 | public function getCannotEmbedFontPolicy() 53 | { 54 | $value = $this->getArgumentValue('-dCannotEmbedFontPolicy'); 55 | if (null === $value) { 56 | switch ($this->getPdfSettings()) { 57 | case PdfSettings::PREPRESS: 58 | return CannotEmbedFontPolicy::ERROR; 59 | default: 60 | return CannotEmbedFontPolicy::WARNING; 61 | } 62 | } 63 | 64 | return ltrim($value, '/'); 65 | } 66 | 67 | /** 68 | * Set cannot embed font policy 69 | * 70 | * @param string $cannotEmbedFontPolicy 71 | * 72 | * @param \InvalidArgumentException 73 | * 74 | * @return $this 75 | */ 76 | public function setCannotEmbedFontPolicy($cannotEmbedFontPolicy) 77 | { 78 | $cannotEmbedFontPolicy = ltrim($cannotEmbedFontPolicy, '/'); 79 | if (!in_array($cannotEmbedFontPolicy, CannotEmbedFontPolicy::values())) { 80 | throw new \InvalidArgumentException('Invalid cannot embed font policy argument'); 81 | } 82 | 83 | $this->setArgument(sprintf('-dCannotEmbedFontPolicy=/%s', $cannotEmbedFontPolicy)); 84 | 85 | return $this; 86 | } 87 | 88 | /** 89 | * Whether to embed all fonts 90 | * 91 | * @return bool 92 | */ 93 | public function isEmbedAllFonts() 94 | { 95 | $value = $this->getArgumentValue('-dEmbedAllFonts'); 96 | if (null === $value) { 97 | switch ($this->getPdfSettings()) { 98 | case PdfSettings::SCREEN: 99 | return false; 100 | default: 101 | return true; 102 | } 103 | } 104 | 105 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 106 | } 107 | 108 | /** 109 | * Set embed all fonts flag 110 | * 111 | * @param string $embedAllFonts 112 | * 113 | * @return $this 114 | */ 115 | public function setEmbedAllFonts($embedAllFonts) 116 | { 117 | $this->setArgument(sprintf('-dEmbedAllFonts=%s', $embedAllFonts ? 'true' : 'false')); 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Get max subset pct 124 | * 125 | * @return int 126 | */ 127 | public function getMaxSubsetPct() 128 | { 129 | $value = $this->getArgumentValue('-dMaxSubsetPct'); 130 | if (null === $value) { 131 | return 100; 132 | } 133 | 134 | return intval($value); 135 | } 136 | 137 | /** 138 | * Set max subset pct 139 | * 140 | * @param int $maxSubsetPct 141 | * 142 | * @return $this 143 | */ 144 | public function setMaxSubsetPct($maxSubsetPct) 145 | { 146 | $this->setArgument(sprintf('-dMaxSubsetPct=%s', $maxSubsetPct)); 147 | 148 | return $this; 149 | } 150 | 151 | /** 152 | * Whether to subset fonts 153 | * 154 | * @return bool 155 | */ 156 | public function isSubsetFonts() 157 | { 158 | $value = $this->getArgumentValue('-dSubsetFonts'); 159 | if (null === $value) { 160 | return true; 161 | } 162 | 163 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 164 | } 165 | 166 | /** 167 | * Set subset fonts flag 168 | * 169 | * @param bool $subsetFonts 170 | * 171 | * @return $this 172 | */ 173 | public function setSubsetFonts($subsetFonts) 174 | { 175 | $this->setArgument(sprintf('-dSubsetFonts=%s', $subsetFonts ? 'true' : 'false')); 176 | 177 | return $this; 178 | } 179 | } 180 | -------------------------------------------------------------------------------- /src/Device/DistillerParameters/MonoImageCompressionTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\DistillerParameters; 9 | 10 | use GravityMedia\Ghostscript\Enum\ImageDownsampleType; 11 | use GravityMedia\Ghostscript\Enum\MonoImageFilter; 12 | use GravityMedia\Ghostscript\Enum\PdfSettings; 13 | 14 | /** 15 | * The monochrome image compression distiller parameters trait. 16 | * 17 | * @package GravityMedia\Ghostscript\Device\DistillerParameters 18 | * 19 | * @link http://ghostscript.com/doc/current/Ps2pdf.htm 20 | */ 21 | trait MonoImageCompressionTrait 22 | { 23 | /** 24 | * Get argument value 25 | * 26 | * @param string $name 27 | * 28 | * @return null|string 29 | */ 30 | abstract protected function getArgumentValue($name); 31 | 32 | /** 33 | * Set argument 34 | * 35 | * @param string $argument 36 | * 37 | * @return $this 38 | */ 39 | abstract protected function setArgument($argument); 40 | 41 | /** 42 | * Get PDF settings 43 | * 44 | * @return string 45 | */ 46 | abstract public function getPdfSettings(); 47 | 48 | /** 49 | * Whether to anti alias monochrome images 50 | * 51 | * @return bool 52 | */ 53 | public function isAntiAliasMonoImages() 54 | { 55 | $value = $this->getArgumentValue('-dAntiAliasMonoImages'); 56 | if (null === $value) { 57 | return false; 58 | } 59 | 60 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 61 | } 62 | 63 | /** 64 | * Set anti alias monochrome images flag 65 | * 66 | * @param bool $antiAliasMonoImages 67 | * 68 | * @return $this 69 | */ 70 | public function setAntiAliasMonoImages($antiAliasMonoImages) 71 | { 72 | $this->setArgument(sprintf('-dAntiAliasMonoImages=%s', $antiAliasMonoImages ? 'true' : 'false')); 73 | 74 | return $this; 75 | } 76 | 77 | /** 78 | * Whether to downsample monochrome images 79 | * 80 | * @return bool 81 | */ 82 | public function isDownsampleMonoImages() 83 | { 84 | $value = $this->getArgumentValue('-dDownsampleMonoImages'); 85 | if (null === $value) { 86 | switch ($this->getPdfSettings()) { 87 | case PdfSettings::SCREEN: 88 | case PdfSettings::EBOOK: 89 | return true; 90 | default: 91 | return false; 92 | } 93 | } 94 | 95 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 96 | } 97 | 98 | /** 99 | * Set downsample monochrome images flag 100 | * 101 | * @param bool $downsampleMonoImages 102 | * 103 | * @return $this 104 | */ 105 | public function setDownsampleMonoImages($downsampleMonoImages) 106 | { 107 | $this->setArgument(sprintf('-dDownsampleMonoImages=%s', $downsampleMonoImages ? 'true' : 'false')); 108 | 109 | return $this; 110 | } 111 | 112 | /** 113 | * Whether to encode monochrome images 114 | * 115 | * @return bool 116 | */ 117 | public function isEncodeMonoImages() 118 | { 119 | $value = $this->getArgumentValue('-dEncodeMonoImages'); 120 | if (null === $value) { 121 | return true; 122 | } 123 | 124 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 125 | } 126 | 127 | /** 128 | * Set encode monochrome images flag 129 | * 130 | * @param bool $encodeMonoImages 131 | * 132 | * @return $this 133 | */ 134 | public function setEncodeMonoImages($encodeMonoImages) 135 | { 136 | $this->setArgument(sprintf('-dEncodeMonoImages=%s', $encodeMonoImages ? 'true' : 'false')); 137 | 138 | return $this; 139 | } 140 | 141 | /** 142 | * Get monochrome image depth 143 | * 144 | * @return int 145 | */ 146 | public function getMonoImageDepth() 147 | { 148 | $value = $this->getArgumentValue('-dMonoImageDepth'); 149 | if (null === $value) { 150 | return -1; 151 | } 152 | 153 | return intval($value); 154 | } 155 | 156 | /** 157 | * Set monochrome image depth 158 | * 159 | * @param int $monoImageDepth 160 | * 161 | * @return $this 162 | */ 163 | public function setMonoImageDepth($monoImageDepth) 164 | { 165 | $this->setArgument(sprintf('-dMonoImageDepth=%s', $monoImageDepth)); 166 | 167 | return $this; 168 | } 169 | 170 | /** 171 | * Get monochrome image downsample threshold 172 | * 173 | * @return float 174 | */ 175 | public function getMonoImageDownsampleThreshold() 176 | { 177 | $value = $this->getArgumentValue('-dMonoImageDownsampleThreshold'); 178 | if (null === $value) { 179 | return 1.5; 180 | } 181 | 182 | return floatval($value); 183 | } 184 | 185 | /** 186 | * Set monochrome image downsample threshold 187 | * 188 | * @param float $monoImageDownsampleThreshold 189 | * 190 | * @return $this 191 | */ 192 | public function setMonoImageDownsampleThreshold($monoImageDownsampleThreshold) 193 | { 194 | $this->setArgument(sprintf('-dMonoImageDownsampleThreshold=%s', $monoImageDownsampleThreshold)); 195 | 196 | return $this; 197 | } 198 | 199 | /** 200 | * Get monochrome image downsample type 201 | * 202 | * @return string 203 | */ 204 | public function getMonoImageDownsampleType() 205 | { 206 | $value = $this->getArgumentValue('-dMonoImageDownsampleType'); 207 | if (null === $value) { 208 | switch ($this->getPdfSettings()) { 209 | case PdfSettings::PREPRESS: 210 | return ImageDownsampleType::BICUBIC; 211 | default: 212 | return ImageDownsampleType::SUBSAMPLE; 213 | } 214 | } 215 | 216 | return ltrim($value, '/'); 217 | } 218 | 219 | /** 220 | * Set monochrome image downsample type 221 | * 222 | * @param string $monoImageDownsampleType 223 | * 224 | * @throws \InvalidArgumentException 225 | * 226 | * @return $this 227 | */ 228 | public function setMonoImageDownsampleType($monoImageDownsampleType) 229 | { 230 | $monoImageDownsampleType = ltrim($monoImageDownsampleType, '/'); 231 | if (!in_array($monoImageDownsampleType, ImageDownsampleType::values())) { 232 | throw new \InvalidArgumentException('Invalid monochrome image downsample type argument'); 233 | } 234 | 235 | $this->setArgument(sprintf('-dMonoImageDownsampleType=/%s', $monoImageDownsampleType)); 236 | 237 | return $this; 238 | } 239 | 240 | /** 241 | * Get monochrome image filter 242 | * 243 | * @return string 244 | */ 245 | public function getMonoImageFilter() 246 | { 247 | $value = $this->getArgumentValue('-dMonoImageFilter'); 248 | if (null === $value) { 249 | return MonoImageFilter::CCITT_FAX_ENCODE; 250 | } 251 | 252 | return ltrim($value, '/'); 253 | } 254 | 255 | /** 256 | * Set monochrome image filter 257 | * 258 | * @param string $monoImageFilter 259 | * 260 | * @throws \InvalidArgumentException 261 | * 262 | * @return $this 263 | */ 264 | public function setMonoImageFilter($monoImageFilter) 265 | { 266 | $monoImageFilter = ltrim($monoImageFilter, '/'); 267 | if (!in_array($monoImageFilter, MonoImageFilter::values())) { 268 | throw new \InvalidArgumentException('Invalid monochrome image filter argument'); 269 | } 270 | 271 | $this->setArgument(sprintf('-dMonoImageFilter=/%s', $monoImageFilter)); 272 | 273 | return $this; 274 | } 275 | 276 | /** 277 | * Get monochrome image resolution 278 | * 279 | * @return int 280 | */ 281 | public function getMonoImageResolution() 282 | { 283 | $value = $this->getArgumentValue('-dMonoImageResolution'); 284 | if (null === $value) { 285 | switch ($this->getPdfSettings()) { 286 | case PdfSettings::PRINTER: 287 | case PdfSettings::PREPRESS: 288 | return 1200; 289 | default: 290 | return 300; 291 | } 292 | } 293 | 294 | return intval($value); 295 | } 296 | 297 | /** 298 | * Set monochrome image resolution 299 | * 300 | * @param int $monoImageResolution 301 | * 302 | * @return $this 303 | */ 304 | public function setMonoImageResolution($monoImageResolution) 305 | { 306 | $this->setArgument(sprintf('-dMonoImageResolution=%s', $monoImageResolution)); 307 | 308 | return $this; 309 | } 310 | } 311 | -------------------------------------------------------------------------------- /src/Device/DistillerParameters/PageCompressionTrait.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device\DistillerParameters; 9 | 10 | /** 11 | * The page compression distiller parameters trait. 12 | * 13 | * @package GravityMedia\Ghostscript\Device\DistillerParameters 14 | * 15 | * @link http://ghostscript.com/doc/current/Ps2pdf.htm 16 | */ 17 | trait PageCompressionTrait 18 | { 19 | /** 20 | * Get argument value 21 | * 22 | * @param string $name 23 | * 24 | * @return null|string 25 | */ 26 | abstract protected function getArgumentValue($name); 27 | 28 | /** 29 | * Set argument 30 | * 31 | * @param string $argument 32 | * 33 | * @return $this 34 | */ 35 | abstract protected function setArgument($argument); 36 | 37 | /** 38 | * Whether to compress pages 39 | * 40 | * @return bool 41 | */ 42 | public function isCompressPages() 43 | { 44 | $value = $this->getArgumentValue('-dCompressPages'); 45 | if (null === $value) { 46 | return true; 47 | } 48 | 49 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 50 | } 51 | 52 | /** 53 | * Set compress pages flag 54 | * 55 | * @param true $compressPages 56 | * 57 | * @return $this 58 | */ 59 | public function setCompressPages($compressPages) 60 | { 61 | $this->setArgument(sprintf('-dCompressPages=%s', $compressPages ? 'true' : 'false')); 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * Whether to LZW encode pages 68 | * 69 | * @return bool 70 | */ 71 | public function isLzwEncodePages() 72 | { 73 | $value = $this->getArgumentValue('-dLZWEncodePages'); 74 | if (null === $value) { 75 | return false; 76 | } 77 | 78 | return filter_var($value, FILTER_VALIDATE_BOOLEAN); 79 | } 80 | 81 | /** 82 | * Set LZW encode pages flag 83 | * 84 | * @param string $lzwEncodePages 85 | * 86 | * @return $this 87 | */ 88 | public function setLzwEncodePages($lzwEncodePages) 89 | { 90 | $this->setArgument(sprintf('-dLZWEncodePages=%s', $lzwEncodePages ? 'true' : 'false')); 91 | 92 | return $this; 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/Device/Inkcov.php: -------------------------------------------------------------------------------- 1 | setArgument('-sDEVICE=inkcov')); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/Device/NoDisplay.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device; 9 | 10 | use GravityMedia\Ghostscript\Ghostscript; 11 | use GravityMedia\Ghostscript\GhostscriptInterface; 12 | use GravityMedia\Ghostscript\Process\Arguments; 13 | 14 | /** 15 | * The no display device class. 16 | * 17 | * @package GravityMedia\Ghostscript\Devices 18 | */ 19 | class NoDisplay extends AbstractDevice 20 | { 21 | /** 22 | * Create no display device object. 23 | * 24 | * @param Ghostscript $ghostscript 25 | * @param Arguments $arguments 26 | */ 27 | public function __construct(GhostscriptInterface $ghostscript, Arguments $arguments) 28 | { 29 | parent::__construct($ghostscript, $arguments->setArgument('-dNODISPLAY')); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/Device/PdfInfo.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device; 9 | 10 | use GravityMedia\Ghostscript\Ghostscript; 11 | use GravityMedia\Ghostscript\GhostscriptInterface; 12 | use GravityMedia\Ghostscript\Process\Arguments; 13 | 14 | /** 15 | * The PDF info device class. 16 | * 17 | * This class supports the pdf_info.ps script that is contained in Ghostscript toolbin. 18 | * 19 | * @link http://svn.ghostscript.com/ghostscript/trunk/gs/toolbin/ 20 | * 21 | * @package GravityMedia\Ghostscript\Devices 22 | */ 23 | class PdfInfo extends NoDisplay 24 | { 25 | /** 26 | * The PDF info path. 27 | */ 28 | private string $pdfInfoPath; 29 | 30 | /** 31 | * Create PDF info device object. 32 | * 33 | * @param Ghostscript $ghostscript 34 | * @param Arguments $arguments 35 | * @param string $pdfInfoPath Path to toolbin/pdf_info.ps 36 | */ 37 | public function __construct(GhostscriptInterface $ghostscript, Arguments $arguments, $pdfInfoPath) 38 | { 39 | parent::__construct($ghostscript, $arguments); 40 | 41 | $this->pdfInfoPath = $pdfInfoPath; 42 | } 43 | 44 | /** 45 | * Create process object. 46 | * 47 | * @param string $input Path to PDF file to be examined 48 | * 49 | * @throws \RuntimeException 50 | * 51 | * @return \Symfony\Component\Process\Process 52 | */ 53 | public function createProcess($input = null) 54 | { 55 | if (!is_string($input) || !file_exists($input)) { 56 | throw new \RuntimeException('Input file does not exist'); 57 | } 58 | 59 | $this->setArgument(sprintf('-sFile=%s', $input)); 60 | 61 | return parent::createProcess($this->pdfInfoPath); 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /src/Device/PdfWrite.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Device; 9 | 10 | use GravityMedia\Ghostscript\Enum\PdfSettings; 11 | use GravityMedia\Ghostscript\Enum\ProcessColorModel; 12 | use GravityMedia\Ghostscript\Ghostscript; 13 | use GravityMedia\Ghostscript\GhostscriptInterface; 14 | use GravityMedia\Ghostscript\Input; 15 | use GravityMedia\Ghostscript\Process\Arguments; 16 | 17 | /** 18 | * The PDF write device class. 19 | * 20 | * @package GravityMedia\Ghostscript\Devices 21 | */ 22 | class PdfWrite extends AbstractDevice 23 | { 24 | /** 25 | * Use distiller parameters. 26 | */ 27 | use DistillerParametersTrait; 28 | 29 | /** 30 | * Use color image compression distiller parameters. 31 | */ 32 | use DistillerParameters\ColorImageCompressionTrait; 33 | 34 | /** 35 | * Use grayscale image compression distiller parameters. 36 | */ 37 | use DistillerParameters\GrayImageCompressionTrait; 38 | 39 | /** 40 | * Use monochrome image compression distiller parameters. 41 | */ 42 | use DistillerParameters\MonoImageCompressionTrait; 43 | 44 | /** 45 | * Use page compression distiller parameters. 46 | */ 47 | use DistillerParameters\PageCompressionTrait; 48 | 49 | /** 50 | * Use font distiller parameters. 51 | */ 52 | use DistillerParameters\FontTrait; 53 | 54 | /** 55 | * Use color conversion distiller parameters. 56 | */ 57 | use DistillerParameters\ColorConversionTrait; 58 | 59 | /** 60 | * Use advanced distiller parameters. 61 | */ 62 | use DistillerParameters\AdvancedTrait; 63 | 64 | /** 65 | * Create PDF write device object. 66 | * 67 | * @param Ghostscript $ghostscript 68 | * @param Arguments $arguments 69 | */ 70 | public function __construct(GhostscriptInterface $ghostscript, Arguments $arguments) 71 | { 72 | parent::__construct($ghostscript, $arguments->setArgument('-sDEVICE=pdfwrite')); 73 | 74 | $this->setPdfSettings(PdfSettings::__DEFAULT); 75 | } 76 | 77 | /** 78 | * Get output file. 79 | * 80 | * @return null|string 81 | */ 82 | public function getOutputFile() 83 | { 84 | return $this->getArgumentValue('-sOutputFile'); 85 | } 86 | 87 | /** 88 | * Set output file. 89 | * 90 | * @param string $outputFile 91 | * 92 | * @return $this 93 | */ 94 | public function setOutputFile($outputFile) 95 | { 96 | $this->setArgument('-sOutputFile=' . $outputFile); 97 | 98 | return $this; 99 | } 100 | 101 | /** 102 | * Get PDF settings. 103 | * 104 | * @return string 105 | */ 106 | public function getPdfSettings() 107 | { 108 | return ltrim($this->getArgumentValue('-dPDFSETTINGS'), '/'); 109 | } 110 | 111 | /** 112 | * Set PDF settings. 113 | * 114 | * @param string $pdfSettings 115 | * 116 | * @throws \InvalidArgumentException 117 | * 118 | * @return $this 119 | */ 120 | public function setPdfSettings($pdfSettings) 121 | { 122 | $pdfSettings = ltrim($pdfSettings, '/'); 123 | if (!in_array($pdfSettings, PdfSettings::values())) { 124 | throw new \InvalidArgumentException('Invalid PDF settings argument'); 125 | } 126 | 127 | $this->setArgument(sprintf('-dPDFSETTINGS=/%s', $pdfSettings)); 128 | 129 | return $this; 130 | } 131 | 132 | /** 133 | * Get process color model. 134 | * 135 | * @return string 136 | */ 137 | public function getProcessColorModel() 138 | { 139 | return ltrim($this->getArgumentValue('-dProcessColorModel'), '/'); 140 | } 141 | 142 | /** 143 | * Set process color model. 144 | * 145 | * @param string $processColorModel 146 | * 147 | * @throws \InvalidArgumentException 148 | * 149 | * @return $this 150 | */ 151 | public function setProcessColorModel($processColorModel) 152 | { 153 | $processColorModel = ltrim($processColorModel, '/'); 154 | if (!in_array($processColorModel, ProcessColorModel::values())) { 155 | throw new \InvalidArgumentException('Invalid process color model argument'); 156 | } 157 | 158 | $this->setArgument(sprintf('-dProcessColorModel=/%s', $processColorModel)); 159 | 160 | return $this; 161 | } 162 | 163 | /** 164 | * {@inheritdoc} 165 | */ 166 | protected function createProcessArguments(Input $input) 167 | { 168 | $code = $input->getPostScriptCode(); 169 | if (null === $code) { 170 | $code = ''; 171 | } 172 | 173 | /** 174 | * Make sure .setpdfwrite gets called when using Ghostscript version less than 9.50: 175 | * This operator conditions the environment for the pdfwrite output device. It is a shorthand for setting parameters 176 | * that have been deemed benificial. While not strictly necessary, it is usually helpful to set call this when using 177 | * the pdfwrite device. 178 | * @link https://ghostscript.com/doc/current/Language.htm#.setpdfwrite 179 | */ 180 | if (version_compare($this->ghostscript->getVersion(), '9.50', '<') && false === strstr($code, '.setpdfwrite')) { 181 | $input->setPostScriptCode(ltrim($code . ' .setpdfwrite', ' ')); 182 | } 183 | 184 | return parent::createProcessArguments($input); 185 | } 186 | } 187 | -------------------------------------------------------------------------------- /src/Enum/AutoRotatePages.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The auto rotate pages enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class AutoRotatePages 16 | { 17 | /** 18 | * Do not auto rotate pages 19 | */ 20 | const NONE = 'None'; 21 | 22 | /** 23 | * Auto rotate all pages 24 | */ 25 | const ALL = 'All'; 26 | 27 | /** 28 | * Auto rotate page by page 29 | */ 30 | const PAGE_BY_PAGE = 'PageByPage'; 31 | 32 | /** 33 | * Available auto rotate pages values 34 | * 35 | * @var string[] $values 36 | */ 37 | private static $values = [ 38 | self::NONE, 39 | self::ALL, 40 | self::PAGE_BY_PAGE 41 | ]; 42 | 43 | /** 44 | * Get available auto rotate pages values 45 | * 46 | * @return string[] 47 | */ 48 | public static function values() 49 | { 50 | return self::$values; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Enum/Binding.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The binding enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class Binding 16 | { 17 | /** 18 | * Left binding 19 | */ 20 | const LEFT = 'Left'; 21 | 22 | /** 23 | * Right binding 24 | */ 25 | const RIGHT = 'Right'; 26 | 27 | /** 28 | * Available binding values 29 | * 30 | * @var string[] $values 31 | */ 32 | private static $values = [ 33 | self::LEFT, 34 | self::RIGHT 35 | ]; 36 | 37 | /** 38 | * Get available binding values 39 | * 40 | * @return string[] 41 | */ 42 | public static function values() 43 | { 44 | return self::$values; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Enum/CannotEmbedFontPolicy.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The cannot embed font policy enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class CannotEmbedFontPolicy 16 | { 17 | /** 18 | * Ignore non embeddable fonts and continue 19 | */ 20 | const OK = 'OK'; 21 | 22 | /** 23 | * Display a warning for non embeddable fonts 24 | */ 25 | const WARNING = 'Warning'; 26 | 27 | /** 28 | * Quit current job for non embeddable fonts 29 | */ 30 | const ERROR = 'Error'; 31 | 32 | /** 33 | * Available cannot embed font policy values 34 | * 35 | * @var string[] 36 | */ 37 | private static $values = [ 38 | self::OK, 39 | self::WARNING, 40 | self::ERROR 41 | ]; 42 | 43 | /** 44 | * Get available cannot embed font policy values 45 | * 46 | * @return string[] 47 | */ 48 | public static function values() 49 | { 50 | return self::$values; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Enum/ColorAndGrayImageFilter.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The color and grayscale image filter enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class ColorAndGrayImageFilter 16 | { 17 | /** 18 | * Select JPEG compression 19 | */ 20 | const DCT_ENCODE = 'DCTEncode'; 21 | 22 | /** 23 | * Select Flate (ZIP) compression 24 | */ 25 | const FLATE_ENCODE = 'FlateEncode'; 26 | 27 | /** 28 | * Available color and grayscale image filter values 29 | * 30 | * @var string[] 31 | */ 32 | private static $values = [ 33 | self::DCT_ENCODE, 34 | self::FLATE_ENCODE 35 | ]; 36 | 37 | /** 38 | * Get available color and grayscale image filter values 39 | * 40 | * @return string[] 41 | */ 42 | public static function values() 43 | { 44 | return self::$values; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Enum/ColorConversionStrategy.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The color conversion strategy enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class ColorConversionStrategy 16 | { 17 | /** 18 | * Leave color unchanged 19 | */ 20 | const LEAVE_COLOR_UNCHANGED = 'LeaveColorUnchanged'; 21 | 22 | /** 23 | * Tag everything for color management 24 | */ 25 | const USE_DEVICE_INDEPENDENT_COLOR = 'UseDeviceIndependentColor'; 26 | 27 | /** 28 | * Convert all colors to gray 29 | */ 30 | const GRAY = 'Gray'; 31 | 32 | /** 33 | * Convert all colors to sRGB 34 | */ 35 | const SRGB = 'sRGB'; 36 | 37 | /** 38 | * Convert all colors to CMYK 39 | */ 40 | const CMYK = 'CMYK'; 41 | 42 | /** 43 | * Available color conversion strategy values 44 | * 45 | * @var string[] 46 | */ 47 | private static $values = [ 48 | self::LEAVE_COLOR_UNCHANGED, 49 | self::USE_DEVICE_INDEPENDENT_COLOR, 50 | self::GRAY, 51 | self::SRGB, 52 | self::CMYK 53 | ]; 54 | 55 | /** 56 | * Get available color conversion strategy values 57 | * 58 | * @return string[] 59 | */ 60 | public static function values() 61 | { 62 | return self::$values; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Enum/DefaultRenderingIntent.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The default rendering intent enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class DefaultRenderingIntent 16 | { 17 | /** 18 | * Write no rendering intent to the PDF 19 | */ 20 | const __DEFAULT = 'Default'; 21 | 22 | /** 23 | * Perceptual rendering intent 24 | */ 25 | const PERCEPTUAL = 'Perceptual'; 26 | 27 | /** 28 | * Saturation rendering intent 29 | */ 30 | const SATURATION = 'Saturation'; 31 | 32 | /** 33 | * Relative colorimetric rendering intent 34 | */ 35 | const RELATIVE_COLORIMETRIC = 'RelativeColorimetric'; 36 | 37 | /** 38 | * Absolute colorimetric rendering intent 39 | */ 40 | const ABSOLUTE_COLORIMETRIC = 'AbsoluteColorimetric'; 41 | 42 | /** 43 | * Available default rendering intent values 44 | * 45 | * @var string[] 46 | */ 47 | private static $values = [ 48 | self::__DEFAULT, 49 | self::PERCEPTUAL, 50 | self::SATURATION, 51 | self::RELATIVE_COLORIMETRIC, 52 | self::ABSOLUTE_COLORIMETRIC 53 | ]; 54 | 55 | /** 56 | * Get available default rendering intent values 57 | * 58 | * @return string[] 59 | */ 60 | public static function values() 61 | { 62 | return self::$values; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Enum/ImageDownsampleType.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The image downsample type enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class ImageDownsampleType 16 | { 17 | /** 18 | * Average groups of samples to get the downsampled value 19 | */ 20 | const AVERAGE = 'Average'; 21 | 22 | /** 23 | * Use bicubic interpolation on a group of samples to get the downsampled value 24 | */ 25 | const BICUBIC = 'Bicubic'; 26 | 27 | /** 28 | * Pick the center sample from a group of samples to get the downsampled value 29 | */ 30 | const SUBSAMPLE = 'Subsample'; 31 | 32 | /** 33 | * Do not downsample images 34 | */ 35 | const NONE = 'None'; 36 | 37 | /** 38 | * Available image downsample type values 39 | * 40 | * @var string[] 41 | */ 42 | private static $values = [ 43 | self::AVERAGE, 44 | self::BICUBIC, 45 | self::SUBSAMPLE, 46 | self::NONE, 47 | ]; 48 | 49 | /** 50 | * Get available image downsample type values 51 | * 52 | * @return string[] 53 | */ 54 | public static function values() 55 | { 56 | return self::$values; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Enum/MonoImageFilter.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The monochrome image filter enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class MonoImageFilter 16 | { 17 | /** 18 | * Select CCITT Group 3 or 4 facsimile encoding 19 | */ 20 | const CCITT_FAX_ENCODE = 'CCITTFaxEncode'; 21 | 22 | /** 23 | * Select Flate (ZIP) compression 24 | */ 25 | const FLATE_ENCODE = 'FlateEncode'; 26 | 27 | /** 28 | * Select run length encoding 29 | */ 30 | const RUN_LENGTH_ENCODE = 'RunLengthEncode'; 31 | 32 | /** 33 | * Available monochrome image filter values 34 | * 35 | * @var string[] 36 | */ 37 | private static $values = [ 38 | self::CCITT_FAX_ENCODE, 39 | self::FLATE_ENCODE, 40 | self::RUN_LENGTH_ENCODE 41 | ]; 42 | 43 | /** 44 | * Get available monochrome image filter values 45 | * 46 | * @return string[] 47 | */ 48 | public static function values() 49 | { 50 | return self::$values; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Enum/PdfSettings.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The PDF settings enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class PdfSettings 16 | { 17 | /** 18 | * Output intended to be useful across a wide variety of uses, possibly at the expense of a larger output file 19 | */ 20 | const __DEFAULT = 'default'; 21 | 22 | /** 23 | * Low-resolution output similar to the Acrobat Distiller "Screen Optimized" setting 24 | */ 25 | const SCREEN = 'screen'; 26 | 27 | /** 28 | * Medium-resolution output similar to the Acrobat Distiller "eBook" setting 29 | */ 30 | const EBOOK = 'ebook'; 31 | 32 | /** 33 | * Output similar to the Acrobat Distiller "Print Optimized" setting 34 | */ 35 | const PRINTER = 'printer'; 36 | 37 | /** 38 | * Output similar to Acrobat Distiller "Prepress Optimized" setting 39 | */ 40 | const PREPRESS = 'prepress'; 41 | 42 | /** 43 | * Available PDF settings values 44 | * 45 | * @var string[] $values 46 | */ 47 | private static $values = [ 48 | self::__DEFAULT, 49 | self::SCREEN, 50 | self::EBOOK, 51 | self::PRINTER, 52 | self::PREPRESS 53 | ]; 54 | 55 | /** 56 | * Get available PDF settings values 57 | * 58 | * @return string[] 59 | */ 60 | public static function values() 61 | { 62 | return self::$values; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/Enum/ProcessColorModel.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The process color model enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class ProcessColorModel 16 | { 17 | const DEVICE_RGB = 'DeviceRGB'; 18 | const DEVICE_CMYK = 'DeviceCMYK'; 19 | const DEVICE_GRAY = 'DeviceGray'; 20 | 21 | 22 | /** 23 | * Available process color model values 24 | * 25 | * @var string[] $values 26 | */ 27 | private static $values = [ 28 | self::DEVICE_RGB, 29 | self::DEVICE_CMYK, 30 | self::DEVICE_GRAY 31 | ]; 32 | 33 | /** 34 | * Get available process color model values 35 | * 36 | * @return string[] 37 | */ 38 | public static function values() 39 | { 40 | return self::$values; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/Enum/TransferFunctionInfo.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The transfer function info enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class TransferFunctionInfo 16 | { 17 | /** 18 | * Preserve transfer functions (pass into the PDF file) 19 | */ 20 | const PRESERVE = 'Preserve'; 21 | 22 | /** 23 | * Ignore transfer functions (do not pass into the PDF file) 24 | */ 25 | const REMOVE = 'Remove'; 26 | 27 | /** 28 | * Apply transfer functions to color values 29 | */ 30 | const APPLY = 'Apply'; 31 | 32 | /** 33 | * Available transfer function info values 34 | * 35 | * @var string[] 36 | */ 37 | private static $values = [ 38 | self::PRESERVE, 39 | self::REMOVE, 40 | self::APPLY 41 | ]; 42 | 43 | /** 44 | * Get available transfer function info values 45 | * 46 | * @return string[] 47 | */ 48 | public static function values() 49 | { 50 | return self::$values; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Enum/UcrAndBgInfo.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Enum; 9 | 10 | /** 11 | * The UCR and BG info enum 12 | * 13 | * @package GravityMedia\Ghostscript\Enum 14 | */ 15 | class UcrAndBgInfo 16 | { 17 | /** 18 | * Preserve under color removal and black generation arguments 19 | */ 20 | const PRESERVE = 'Preserve'; 21 | 22 | /** 23 | * Ignore under color removal and black generation arguments 24 | */ 25 | const REMOVE = 'Remove'; 26 | 27 | /** 28 | * Available UCR and BG info values 29 | * 30 | * @var string[] 31 | */ 32 | private static $values = [ 33 | self::PRESERVE, 34 | self::REMOVE 35 | ]; 36 | 37 | /** 38 | * Get available UCR and BG info values 39 | * 40 | * @return string[] 41 | */ 42 | public static function values() 43 | { 44 | return self::$values; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/Ghostscript.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript; 9 | 10 | use GravityMedia\Ghostscript\Device\BoundingBoxInfo; 11 | use GravityMedia\Ghostscript\Device\Inkcov; 12 | use GravityMedia\Ghostscript\Device\NoDisplay; 13 | use GravityMedia\Ghostscript\Device\PdfInfo; 14 | use GravityMedia\Ghostscript\Device\PdfWrite; 15 | use GravityMedia\Ghostscript\Process\Arguments; 16 | use Symfony\Component\Process\Process; 17 | 18 | /** 19 | * The Ghostscript class. 20 | * 21 | * @package GravityMedia\Ghostscript 22 | */ 23 | class Ghostscript implements GhostscriptInterface 24 | { 25 | /** 26 | * The default binary. 27 | */ 28 | const DEFAULT_BINARY = 'gs'; 29 | 30 | /** 31 | * The versions. 32 | * 33 | * @var string[] 34 | */ 35 | protected static $versions = []; 36 | 37 | /** 38 | * The options. 39 | * 40 | * @var array 41 | */ 42 | protected $options = []; 43 | 44 | 45 | /** 46 | * Create Ghostscript object. 47 | * 48 | * @param array $options 49 | * 50 | * @throws \RuntimeException 51 | */ 52 | public function __construct(array $options = []) 53 | { 54 | $this->options = $options; 55 | } 56 | 57 | /** 58 | * Get option. 59 | * 60 | * @param string $name 61 | * @param mixed $default 62 | * 63 | * @return mixed 64 | */ 65 | public function getOption($name, $default = null) 66 | { 67 | if (array_key_exists($name, $this->options)) { 68 | return $this->options[$name]; 69 | } 70 | 71 | return $default; 72 | } 73 | 74 | /** 75 | * Get process to identify version. 76 | * 77 | * @param string $binary 78 | * 79 | * @return Process 80 | */ 81 | protected function createProcessToIdentifyVersion($binary) 82 | { 83 | return new Process([$binary, '--version']); 84 | } 85 | 86 | /** 87 | * Get version. 88 | * 89 | * @throws \RuntimeException 90 | * 91 | * @return string 92 | */ 93 | public function getVersion() 94 | { 95 | $binary = $this->getOption('bin', static::DEFAULT_BINARY); 96 | 97 | if (!isset(static::$versions[$binary])) { 98 | $process = $this->createProcessToIdentifyVersion($binary); 99 | $process->run(); 100 | 101 | if (!$process->isSuccessful()) { 102 | throw new \RuntimeException($process->getErrorOutput()); 103 | } 104 | 105 | static::$versions[$binary] = $process->getOutput(); 106 | } 107 | 108 | return static::$versions[$binary]; 109 | } 110 | 111 | /** 112 | * Create arguments object. 113 | * 114 | * @return Arguments 115 | */ 116 | protected function createArguments() 117 | { 118 | $arguments = new Arguments(); 119 | 120 | if ($this->getOption('quiet', true)) { 121 | $arguments->addArgument('-q'); 122 | } 123 | 124 | return $arguments; 125 | } 126 | 127 | /** 128 | * Create PDF device object. 129 | * 130 | * @param null|string $outputFile 131 | * 132 | * @return PdfWrite 133 | */ 134 | public function createPdfDevice($outputFile = null) 135 | { 136 | $device = new PdfWrite($this, $this->createArguments()); 137 | $device 138 | ->setSafer() 139 | ->setBatch() 140 | ->setNoPause(); 141 | 142 | if (null === $outputFile) { 143 | $outputFile = '-'; 144 | } 145 | 146 | $device->setOutputFile($outputFile); 147 | 148 | return $device; 149 | } 150 | 151 | /** 152 | * Create no display device object. 153 | * 154 | * @return NoDisplay 155 | */ 156 | public function createNoDisplayDevice() 157 | { 158 | return new NoDisplay($this, $this->createArguments()); 159 | } 160 | 161 | /** 162 | * Create PDF info device object. 163 | * 164 | * @param string $pdfInfoPath Path to toolbin/pdf_info.ps 165 | * 166 | * @return PdfInfo 167 | */ 168 | public function createPdfInfoDevice($pdfInfoPath) 169 | { 170 | return new PdfInfo($this, $this->createArguments(), $pdfInfoPath); 171 | } 172 | 173 | /** 174 | * Create bounding box info device object. 175 | * 176 | * @return BoundingBoxInfo 177 | */ 178 | public function createBoundingBoxInfoDevice() 179 | { 180 | $device = new BoundingBoxInfo($this, $this->createArguments()); 181 | $device 182 | ->setSafer() 183 | ->setBatch() 184 | ->setNoPause(); 185 | 186 | return $device; 187 | } 188 | 189 | /** 190 | * Create inkcov device object 191 | * 192 | * @return Inkcov 193 | */ 194 | public function createInkcovDevice() 195 | { 196 | $this->options['quiet'] = false; 197 | 198 | $arguments = $this->createArguments(); 199 | $arguments->addArgument('-o'); 200 | $arguments->addArgument('-'); 201 | 202 | $device = new Inkcov($this, $arguments); 203 | 204 | return $device; 205 | } 206 | } 207 | -------------------------------------------------------------------------------- /src/GhostscriptInterface.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript; 9 | 10 | use GravityMedia\Ghostscript\Device\BoundingBoxInfo; 11 | use GravityMedia\Ghostscript\Device\Inkcov; 12 | use GravityMedia\Ghostscript\Device\NoDisplay; 13 | use GravityMedia\Ghostscript\Device\PdfInfo; 14 | use GravityMedia\Ghostscript\Device\PdfWrite; 15 | 16 | /** 17 | * @package GravityMedia\Ghostscript 18 | */ 19 | interface GhostscriptInterface 20 | { 21 | /** 22 | * Get option. 23 | * 24 | * @param string $name 25 | * @param mixed $default 26 | * 27 | * @return mixed 28 | */ 29 | public function getOption($name, $default = null); 30 | 31 | /** 32 | * Get version. 33 | * 34 | * @return string 35 | * @throws \RuntimeException 36 | * 37 | */ 38 | public function getVersion(); 39 | 40 | /** 41 | * Create PDF device object. 42 | * 43 | * @param null|string $outputFile 44 | * 45 | * @return PdfWrite 46 | */ 47 | public function createPdfDevice($outputFile = null); 48 | 49 | /** 50 | * Create no display device object. 51 | * 52 | * @return NoDisplay 53 | */ 54 | public function createNoDisplayDevice(); 55 | 56 | /** 57 | * Create PDF info device object. 58 | * 59 | * @param string $pdfInfoPath Path to toolbin/pdf_info.ps 60 | * 61 | * @return PdfInfo 62 | */ 63 | public function createPdfInfoDevice($pdfInfoPath); 64 | 65 | /** 66 | * Create bounding box info device object. 67 | * 68 | * @return BoundingBoxInfo 69 | */ 70 | public function createBoundingBoxInfoDevice(); 71 | 72 | /** 73 | * Create inkcov device object 74 | * 75 | * @return Inkcov 76 | */ 77 | public function createInkcovDevice(); 78 | } 79 | -------------------------------------------------------------------------------- /src/Input.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript; 9 | 10 | use Symfony\Component\Process\ProcessUtils; 11 | 12 | /** 13 | * The input class. 14 | * 15 | * @package GravityMedia\Ghostscript 16 | */ 17 | class Input 18 | { 19 | /** 20 | * The process input. 21 | * 22 | * @var null|string|resource 23 | */ 24 | private $processInput; 25 | 26 | /** 27 | * The PostScript code. 28 | * 29 | * @var null|string 30 | */ 31 | private $postScriptCode; 32 | 33 | /** 34 | * The files. 35 | * 36 | * @var null|string[] 37 | */ 38 | private $files; 39 | 40 | /** 41 | * Get process input. 42 | * 43 | * @return null|string|resource 44 | */ 45 | public function getProcessInput() 46 | { 47 | return $this->processInput; 48 | } 49 | 50 | /** 51 | * Set process input. 52 | * 53 | * @param mixed $processInput 54 | * 55 | * @throws \InvalidArgumentException 56 | * 57 | * @return $this 58 | */ 59 | public function setProcessInput($processInput) 60 | { 61 | $this->processInput = ProcessUtils::validateInput(__METHOD__, $processInput); 62 | 63 | return $this; 64 | } 65 | 66 | /** 67 | * Get PostScript code. 68 | * 69 | * @return null|string 70 | */ 71 | public function getPostScriptCode() 72 | { 73 | return $this->postScriptCode; 74 | } 75 | 76 | /** 77 | * Set PostScript code. 78 | * 79 | * @param null|string $postScriptCode 80 | * 81 | * @return $this 82 | */ 83 | public function setPostScriptCode($postScriptCode) 84 | { 85 | $this->postScriptCode = $postScriptCode; 86 | 87 | return $this; 88 | } 89 | 90 | /** 91 | * Get files. 92 | * 93 | * @return string[] 94 | */ 95 | public function getFiles() 96 | { 97 | if (null === $this->files) { 98 | return []; 99 | } 100 | 101 | return $this->files; 102 | } 103 | 104 | /** 105 | * Add file. 106 | * 107 | * @param string $file 108 | * 109 | * @return $this 110 | */ 111 | public function addFile($file) 112 | { 113 | if (null === $this->files) { 114 | $this->files = []; 115 | } 116 | 117 | $this->files[] = $file; 118 | 119 | return $this; 120 | } 121 | 122 | /** 123 | * Set files. 124 | * 125 | * @param string[] $files 126 | * 127 | * @return $this 128 | */ 129 | public function setFiles(array $files) 130 | { 131 | $this->files = $files; 132 | 133 | return $this; 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/Process/Argument.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Process; 9 | 10 | /** 11 | * The argument class. 12 | * 13 | * @package GravityMedia\Ghostscript\Process 14 | */ 15 | class Argument 16 | { 17 | /** 18 | * The name. 19 | * 20 | * @var string 21 | */ 22 | protected $name; 23 | 24 | /** 25 | * The value. 26 | * 27 | * @var mixed 28 | */ 29 | protected $value; 30 | 31 | /** 32 | * Create argument object. 33 | * 34 | * @param string $name 35 | * @param mixed $value 36 | */ 37 | public function __construct($name, $value = null) 38 | { 39 | $this->name = $name; 40 | $this->value = $value; 41 | } 42 | 43 | /** 44 | * Create argument object from string. 45 | * 46 | * @param string $argument 47 | * 48 | * @return $this 49 | */ 50 | public static function fromString($argument) 51 | { 52 | $argument = explode('=', $argument, 2); 53 | $instance = new static(array_shift($argument)); 54 | 55 | if (count($argument) > 0) { 56 | $instance->setValue(array_shift($argument)); 57 | } 58 | 59 | return $instance; 60 | } 61 | 62 | /** 63 | * Return argument object as string. 64 | * 65 | * @return string 66 | */ 67 | public function toString() 68 | { 69 | if (!$this->hasValue()) { 70 | return $this->getName(); 71 | } 72 | 73 | return sprintf('%s=%s', $this->getName(), $this->getValue()); 74 | } 75 | 76 | /** 77 | * Get name. 78 | * 79 | * @return string 80 | */ 81 | public function getName() 82 | { 83 | return $this->name; 84 | } 85 | 86 | /** 87 | * Return whether the argument has a value. 88 | * 89 | * @return bool 90 | */ 91 | public function hasValue() 92 | { 93 | return null !== $this->value; 94 | } 95 | 96 | /** 97 | * Get value. 98 | * 99 | * @return mixed 100 | */ 101 | public function getValue() 102 | { 103 | return $this->value; 104 | } 105 | 106 | /** 107 | * Set value. 108 | * 109 | * @param mixed $value 110 | * 111 | * @return $this 112 | */ 113 | public function setValue($value) 114 | { 115 | $this->value = $value; 116 | 117 | return $this; 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/Process/Arguments.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\Ghostscript\Process; 9 | 10 | /** 11 | * The arguments class. 12 | * 13 | * @package GravityMedia\Ghostscript\Process 14 | */ 15 | class Arguments 16 | { 17 | /** 18 | * The argument objects. 19 | * 20 | * @var Argument[] 21 | */ 22 | protected $arguments; 23 | 24 | /** 25 | * Create arguments object. 26 | */ 27 | public function __construct() 28 | { 29 | $this->arguments = []; 30 | } 31 | 32 | /** 33 | * Return arguments as array of strings. 34 | * 35 | * @return string[] 36 | */ 37 | public function toArray() 38 | { 39 | return array_values(array_map(function (Argument $argument) { 40 | return $argument->toString(); 41 | }, $this->arguments)); 42 | } 43 | 44 | /** 45 | * Convert argument to argument object. 46 | * 47 | * @param string|Argument $argument 48 | * 49 | * @throws \InvalidArgumentException 50 | * 51 | * @return Argument 52 | */ 53 | protected function convertArgument($argument) 54 | { 55 | if (is_string($argument)) { 56 | $argument = Argument::fromString($argument); 57 | } 58 | 59 | if (!$argument instanceof Argument) { 60 | throw new \InvalidArgumentException('Invalid argument'); 61 | } 62 | 63 | return $argument; 64 | } 65 | 66 | /** 67 | * Get argument object. 68 | * 69 | * @param string $name 70 | * 71 | * @return Argument|null 72 | */ 73 | public function getArgument($name) 74 | { 75 | $hash = $this->hashName($name); 76 | 77 | if (isset($this->arguments[$hash])) { 78 | return $this->arguments[$hash]; 79 | } 80 | 81 | return null; 82 | } 83 | 84 | /** 85 | * Add argument. 86 | * 87 | * @param string|Argument $argument 88 | * 89 | * @throws \InvalidArgumentException 90 | * 91 | * @return $this 92 | */ 93 | public function addArgument($argument) 94 | { 95 | $this->arguments[] = $this->convertArgument($argument); 96 | 97 | return $this; 98 | } 99 | 100 | /** 101 | * Add all arguments. 102 | * 103 | * @param array $arguments 104 | * 105 | * @throws \InvalidArgumentException 106 | * 107 | * @return $this 108 | */ 109 | public function addArguments(array $arguments) 110 | { 111 | foreach ($arguments as $argument) { 112 | $this->addArgument($argument); 113 | } 114 | 115 | return $this; 116 | } 117 | 118 | /** 119 | * Hash the name. 120 | * 121 | * @param string $name 122 | * 123 | * @return string 124 | */ 125 | protected function hashName($name) 126 | { 127 | return strtolower(ltrim($name, '-')); 128 | } 129 | 130 | /** 131 | * Set argument. 132 | * 133 | * @param string|Argument $argument 134 | * 135 | * @throws \InvalidArgumentException 136 | * 137 | * @return $this 138 | */ 139 | public function setArgument($argument) 140 | { 141 | $argument = $this->convertArgument($argument); 142 | 143 | $hash = $this->hashName($argument->getName()); 144 | 145 | $this->arguments[$hash] = $argument; 146 | 147 | return $this; 148 | } 149 | 150 | /** 151 | * Set all arguments. 152 | * 153 | * @param array $arguments 154 | * 155 | * @throws \InvalidArgumentException 156 | * 157 | * @return $this 158 | */ 159 | public function setArguments(array $arguments) 160 | { 161 | foreach ($arguments as $argument) { 162 | $this->setArgument($argument); 163 | } 164 | 165 | return $this; 166 | } 167 | } 168 | -------------------------------------------------------------------------------- /tests/data/input.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GravityMedia/Ghostscript/156a3da121624ea1057d6732d3f09ceed01aba81/tests/data/input.pdf -------------------------------------------------------------------------------- /tests/data/pdf_info.ps: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GravityMedia/Ghostscript/156a3da121624ea1057d6732d3f09ceed01aba81/tests/data/pdf_info.ps -------------------------------------------------------------------------------- /tests/src/Device/AbstractDeviceTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device; 9 | 10 | use GravityMedia\Ghostscript\Device\AbstractDevice; 11 | use GravityMedia\Ghostscript\Ghostscript; 12 | use GravityMedia\Ghostscript\Input; 13 | use GravityMedia\Ghostscript\Process\Argument; 14 | use GravityMedia\Ghostscript\Process\Arguments; 15 | use PHPUnit\Framework\Attributes\CoversClass; 16 | use PHPUnit\Framework\Attributes\UsesClass; 17 | use PHPUnit\Framework\TestCase; 18 | 19 | /** 20 | * The abstract device test class. 21 | * 22 | * @package GravityMedia\GhostscriptTest\Devices 23 | */ 24 | #[CoversClass(\GravityMedia\Ghostscript\Device\AbstractDevice::class)] 25 | #[UsesClass(\GravityMedia\Ghostscript\Ghostscript::class)] 26 | #[UsesClass(\GravityMedia\Ghostscript\Input::class)] 27 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\EpsTrait::class)] 28 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\FontTrait::class)] 29 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\IccColorTrait::class)] 30 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\InteractionTrait::class)] 31 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\OtherTrait::class)] 32 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\OutputSelectionTrait::class)] 33 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\PageTrait::class)] 34 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\RenderingTrait::class)] 35 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\ResourceTrait::class)] 36 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 37 | #[UsesClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 38 | class AbstractDeviceTest extends TestCase 39 | { 40 | /** 41 | * Returns an OS independent representation of the commandline. 42 | * 43 | * @param string $commandline 44 | * 45 | * @return mixed 46 | */ 47 | protected function quoteCommandLine($commandline) 48 | { 49 | if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) { 50 | return str_replace('"', '\'', $commandline); 51 | 52 | } 53 | 54 | return $commandline; 55 | } 56 | 57 | /** 58 | * @param array $args 59 | * 60 | * @return AbstractDevice 61 | */ 62 | protected function createDevice(array $args = []) 63 | { 64 | $ghostscript = new Ghostscript(); 65 | $arguments = new Arguments(); 66 | $arguments->setArguments($args); 67 | 68 | return $this->getMockForAbstractClass(AbstractDevice::class, [$ghostscript, $arguments]); 69 | } 70 | 71 | public function testArgumentGetter() 72 | { 73 | $device = $this->createDevice(['-dFoo=/Bar']); 74 | $method = new \ReflectionMethod(AbstractDevice::class, 'getArgument'); 75 | $method->setAccessible(true); 76 | 77 | $this->assertNull($method->invoke($device, '-dBaz')); 78 | 79 | /** @var \GravityMedia\Ghostscript\Process\Argument $argument */ 80 | $argument = $method->invoke($device, '-dFoo'); 81 | $this->assertInstanceOf(Argument::class, $argument); 82 | $this->assertSame('/Bar', $argument->getValue()); 83 | } 84 | 85 | public function testArgumentTester() 86 | { 87 | $device = $this->createDevice(['-dFoo=/Bar']); 88 | $method = new \ReflectionMethod(AbstractDevice::class, 'hasArgument'); 89 | $method->setAccessible(true); 90 | 91 | $this->assertFalse($method->invoke($device, '-dBar')); 92 | $this->assertTrue($method->invoke($device, '-dFoo')); 93 | } 94 | 95 | public function testArgumentValueGetter() 96 | { 97 | $device = $this->createDevice(['-dFoo=/Bar']); 98 | $method = new \ReflectionMethod(AbstractDevice::class, 'getArgumentValue'); 99 | $method->setAccessible(true); 100 | 101 | $this->assertNull($method->invoke($device, '-dBaz')); 102 | $this->assertSame('/Bar', $method->invoke($device, '-dFoo')); 103 | } 104 | 105 | public function testArgumentSetter() 106 | { 107 | $ghostscript = new Ghostscript(); 108 | $arguments = new Arguments(); 109 | 110 | /** @var AbstractDevice $device */ 111 | $device = $this->getMockForAbstractClass(AbstractDevice::class, [$ghostscript, $arguments]); 112 | 113 | $method = new \ReflectionMethod(AbstractDevice::class, 'setArgument'); 114 | $method->setAccessible(true); 115 | $method->invoke($device, '-dFoo=/Bar'); 116 | 117 | $argument = $arguments->getArgument('-dFoo'); 118 | $this->assertInstanceOf(Argument::class, $argument); 119 | $this->assertSame('/Bar', $argument->getValue()); 120 | } 121 | 122 | public function testProcessCreation() 123 | { 124 | $process = $this->createDevice()->createProcess(); 125 | 126 | $this->assertEquals("'gs'", $this->quoteCommandLine($process->getCommandLine())); 127 | } 128 | 129 | public function testProcessCreationWithInput() 130 | { 131 | $file = __DIR__ . '/../../data/input.pdf'; 132 | $processInput = fopen($file, 'r'); 133 | $code = '.setpdfwrite'; 134 | 135 | $input = new Input(); 136 | $input->addFile($file); 137 | $input->setProcessInput($processInput); 138 | $input->setPostScriptCode($code); 139 | 140 | $process = $this->createDevice()->createProcess($input); 141 | 142 | $this->assertEquals("'gs' '-c' '$code' '-f' '$file' '-'", $this->quoteCommandLine($process->getCommandLine())); 143 | $this->assertEquals($processInput, $process->getInput()); 144 | 145 | fclose($processInput); 146 | } 147 | 148 | public function testProcessCreationWithPostScriptInput() 149 | { 150 | $input = '.setpdfwrite'; 151 | 152 | $process = $this->createDevice()->createProcess($input); 153 | 154 | $this->assertEquals("'gs' '-c' '$input'", $this->quoteCommandLine($process->getCommandLine())); 155 | } 156 | 157 | public function testProcessCreationWithFileInput() 158 | { 159 | $input = __DIR__ . '/../../data/input.pdf'; 160 | 161 | $process = $this->createDevice()->createProcess($input); 162 | 163 | $this->assertEquals("'gs' '-f' '$input'", $this->quoteCommandLine($process->getCommandLine())); 164 | } 165 | 166 | public function testProcessCreationWithResourceInput() 167 | { 168 | $input = fopen(__DIR__ . '/../../data/input.pdf', 'r'); 169 | 170 | $process = $this->createDevice()->createProcess($input); 171 | 172 | $this->assertEquals("'gs' '-'", $this->quoteCommandLine($process->getCommandLine())); 173 | $this->assertEquals($input, $process->getInput()); 174 | 175 | fclose($input); 176 | } 177 | 178 | /** 179 | * @expectedException \RuntimeException 180 | */ 181 | public function testProcessCreationThrowsExceptionOnMissingInputFile() 182 | { 183 | $this->expectExceptionMessage('Input file does not exist'); 184 | 185 | $input = new Input(); 186 | $input->addFile('/path/to/input/file.pdf'); 187 | 188 | $this->createDevice()->createProcess($input); 189 | } 190 | } 191 | -------------------------------------------------------------------------------- /tests/src/Device/BoundingBoxInfoTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device; 9 | 10 | use GravityMedia\Ghostscript\Device\AbstractDevice; 11 | use GravityMedia\Ghostscript\Device\BoundingBoxInfo; 12 | use GravityMedia\Ghostscript\Ghostscript; 13 | use GravityMedia\Ghostscript\Process\Argument; 14 | use GravityMedia\Ghostscript\Process\Arguments; 15 | use PHPUnit\Framework\Attributes\CoversClass; 16 | use PHPUnit\Framework\Attributes\UsesClass; 17 | use PHPUnit\Framework\TestCase; 18 | 19 | /** 20 | * The bounding box info device test class. 21 | * 22 | * @package GravityMedia\GhostscriptTest\Devices 23 | */ 24 | #[CoversClass(\GravityMedia\Ghostscript\Device\BoundingBoxInfo::class)] 25 | #[UsesClass(\GravityMedia\Ghostscript\Ghostscript::class)] 26 | #[UsesClass(\GravityMedia\Ghostscript\Device\AbstractDevice::class)] 27 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 28 | #[UsesClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 29 | class BoundingBoxInfoTest extends DeviceTestCase 30 | { 31 | protected function createDevice(?string $version = null): AbstractDevice 32 | { 33 | return new BoundingBoxInfo($this->getGhostscript($version), $this->arguments); 34 | } 35 | 36 | public function testDeviceCreation() 37 | { 38 | $device = $this->createDevice(); 39 | 40 | $this->assertInstanceOf(BoundingBoxInfo::class, $device); 41 | 42 | $argument = $this->arguments->getArgument('-sDEVICE'); 43 | 44 | $this->assertInstanceOf(Argument::class, $argument); 45 | $this->assertEquals('bbox', $argument->getValue()); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /tests/src/Device/CommandLineParameters/FontTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\CommandLineParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\CommandLineParameters\FontTrait; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The font-related parameters trait test class. 16 | * 17 | * @package GravityMedia\GhostscriptTest\Device\CommandLineParameters 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\FontTrait::class)] 20 | class FontTraitTest extends TestCase 21 | { 22 | public function testFontPath() 23 | { 24 | /** @var FontTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 25 | $trait = $this->getMockForTrait(FontTrait::class); 26 | $trait->expects($this->once())->method('getArgumentValue')->with('-sFONTPATH')->willReturn(null); 27 | $this->assertNull($trait->getFontPath()); 28 | 29 | $trait->expects($this->once())->method('setArgument')->with('-sFONTPATH=some/path')->willReturnSelf(); 30 | $this->assertSame($trait, $trait->setFontPath('some/path')); 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /tests/src/Device/CommandLineParameters/InteractionTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\CommandLineParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\CommandLineParameters\InteractionTrait; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The interaction-related parameters trait test class. 16 | * 17 | * @package GravityMedia\GhostscriptTest\Device\CommandLineParameters 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\InteractionTrait::class)] 20 | class InteractionTraitTest extends TestCase 21 | { 22 | public function testBatch() 23 | { 24 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 25 | $trait = $this->getMockForTrait(InteractionTrait::class); 26 | $trait->expects($this->once())->method('hasArgument')->with('-dBATCH')->willReturn(false); 27 | $this->assertFalse($trait->isBatch()); 28 | 29 | $trait->expects($this->once())->method('setArgument')->with('-dBATCH')->willReturnSelf(); 30 | $this->assertSame($trait, $trait->setBatch()); 31 | } 32 | 33 | public function testNoPagePrompt() 34 | { 35 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 36 | $trait = $this->getMockForTrait(InteractionTrait::class); 37 | $trait->expects($this->once())->method('hasArgument')->with('-dNOPAGEPROMPT')->willReturn(false); 38 | $this->assertFalse($trait->isNoPagePrompt()); 39 | 40 | $trait->expects($this->once())->method('setArgument')->with('-dNOPAGEPROMPT')->willReturnSelf(); 41 | $this->assertSame($trait, $trait->setNoPagePrompt()); 42 | } 43 | 44 | public function testNoPause() 45 | { 46 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 47 | $trait = $this->getMockForTrait(InteractionTrait::class); 48 | $trait->expects($this->once())->method('hasArgument')->with('-dNOPAUSE')->willReturn(false); 49 | $this->assertFalse($trait->isNoPause()); 50 | 51 | $trait->expects($this->once())->method('setArgument')->with('-dNOPAUSE')->willReturnSelf(); 52 | $this->assertSame($trait, $trait->setNoPause()); 53 | } 54 | 55 | public function testNoPromt() 56 | { 57 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 58 | $trait = $this->getMockForTrait(InteractionTrait::class); 59 | $trait->expects($this->once())->method('hasArgument')->with('-dNOPROMPT')->willReturn(false); 60 | $this->assertFalse($trait->isNoPrompt()); 61 | 62 | $trait->expects($this->once())->method('setArgument')->with('-dNOPROMPT')->willReturnSelf(); 63 | $this->assertSame($trait, $trait->setNoPrompt()); 64 | } 65 | 66 | public function testQuiet() 67 | { 68 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 69 | $trait = $this->getMockForTrait(InteractionTrait::class); 70 | $trait->expects($this->once())->method('hasArgument')->with('-dQUIET')->willReturn(false); 71 | $this->assertFalse($trait->isQuiet()); 72 | 73 | $trait->expects($this->once())->method('setArgument')->with('-dQUIET')->willReturnSelf(); 74 | $this->assertSame($trait, $trait->setQuiet()); 75 | } 76 | 77 | public function testShortErrors() 78 | { 79 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 80 | $trait = $this->getMockForTrait(InteractionTrait::class); 81 | $trait->expects($this->once())->method('hasArgument')->with('-dSHORTERRORS')->willReturn(false); 82 | $this->assertFalse($trait->isShortErrors()); 83 | 84 | $trait->expects($this->once())->method('setArgument')->with('-dSHORTERRORS')->willReturnSelf(); 85 | $this->assertSame($trait, $trait->setShortErrors()); 86 | } 87 | 88 | public function testStdout() 89 | { 90 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 91 | $trait = $this->getMockForTrait(InteractionTrait::class); 92 | $trait->expects($this->once())->method('getArgumentValue')->with('-sstdout')->willReturn(null); 93 | $this->assertNull($trait->getStdout()); 94 | 95 | $trait->expects($this->once())->method('setArgument')->with('-sstdout=some file')->willReturnSelf(); 96 | $this->assertSame($trait, $trait->setStdout('some file')); 97 | } 98 | 99 | public function testTtyPause() 100 | { 101 | /** @var InteractionTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 102 | $trait = $this->getMockForTrait(InteractionTrait::class); 103 | $trait->expects($this->once())->method('hasArgument')->with('-dTTYPAUSE')->willReturn(false); 104 | $this->assertFalse($trait->isTtyPause()); 105 | 106 | $trait->expects($this->once())->method('setArgument')->with('-dTTYPAUSE')->willReturnSelf(); 107 | $this->assertSame($trait, $trait->setTtyPause()); 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /tests/src/Device/CommandLineParameters/OtherTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\CommandLineParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\CommandLineParameters\OtherTrait; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The other parameters trait test class. 16 | * 17 | * @package GravityMedia\GhostscriptTest\Device\CommandLineParameters 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\OtherTrait::class)] 20 | class OtherTraitTest extends TestCase 21 | { 22 | public function testFilterImage() 23 | { 24 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 25 | $trait = $this->getMockForTrait(OtherTrait::class); 26 | $trait->expects($this->once())->method('hasArgument')->with('-dFILTERIMAGE')->willReturn(false); 27 | $this->assertFalse($trait->isFilterImage()); 28 | 29 | $trait->expects($this->once())->method('setArgument')->with('-dFILTERIMAGE')->willReturnSelf(); 30 | $this->assertSame($trait, $trait->setFilterImage()); 31 | } 32 | 33 | public function testFilterText() 34 | { 35 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 36 | $trait = $this->getMockForTrait(OtherTrait::class); 37 | $trait->expects($this->once())->method('hasArgument')->with('-dFILTERTEXT')->willReturn(false); 38 | $this->assertFalse($trait->isFilterText()); 39 | 40 | $trait->expects($this->once())->method('setArgument')->with('-dFILTERTEXT')->willReturnSelf(); 41 | $this->assertSame($trait, $trait->setFilterText()); 42 | } 43 | 44 | public function testFilterVector() 45 | { 46 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 47 | $trait = $this->getMockForTrait(OtherTrait::class); 48 | $trait->expects($this->once())->method('hasArgument')->with('-dFILTERVECTOR')->willReturn(false); 49 | $this->assertFalse($trait->isFilterVector()); 50 | 51 | $trait->expects($this->once())->method('setArgument')->with('-dFILTERVECTOR')->willReturnSelf(); 52 | $this->assertSame($trait, $trait->setFilterVector()); 53 | } 54 | 55 | public function testDelayBind() 56 | { 57 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 58 | $trait = $this->getMockForTrait(OtherTrait::class); 59 | $trait->expects($this->once())->method('hasArgument')->with('-dDELAYBIND')->willReturn(false); 60 | $this->assertFalse($trait->isDelayBind()); 61 | 62 | $trait->expects($this->once())->method('setArgument')->with('-dDELAYBIND')->willReturnSelf(); 63 | $this->assertSame($trait, $trait->setDelayBind()); 64 | } 65 | 66 | public function testDoPdfMarks() 67 | { 68 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 69 | $trait = $this->getMockForTrait(OtherTrait::class); 70 | $trait->expects($this->once())->method('hasArgument')->with('-dDOPDFMARKS')->willReturn(false); 71 | $this->assertFalse($trait->isDoPdfMarks()); 72 | 73 | $trait->expects($this->once())->method('setArgument')->with('-dDOPDFMARKS')->willReturnSelf(); 74 | $this->assertSame($trait, $trait->setDoPdfMarks()); 75 | } 76 | 77 | public function testJobServer() 78 | { 79 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 80 | $trait = $this->getMockForTrait(OtherTrait::class); 81 | $trait->expects($this->once())->method('hasArgument')->with('-dJOBSERVER')->willReturn(false); 82 | $this->assertFalse($trait->isJobServer()); 83 | 84 | $trait->expects($this->once())->method('setArgument')->with('-dJOBSERVER')->willReturnSelf(); 85 | $this->assertSame($trait, $trait->setJobServer()); 86 | } 87 | 88 | public function testNoBind() 89 | { 90 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 91 | $trait = $this->getMockForTrait(OtherTrait::class); 92 | $trait->expects($this->once())->method('hasArgument')->with('-dNOBIND')->willReturn(false); 93 | $this->assertFalse($trait->isNoBind()); 94 | 95 | $trait->expects($this->once())->method('setArgument')->with('-dNOBIND')->willReturnSelf(); 96 | $this->assertSame($trait, $trait->setNoBind()); 97 | } 98 | 99 | public function testNoCache() 100 | { 101 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 102 | $trait = $this->getMockForTrait(OtherTrait::class); 103 | $trait->expects($this->once())->method('hasArgument')->with('-dNOCACHE')->willReturn(false); 104 | $this->assertFalse($trait->isNoCache()); 105 | 106 | $trait->expects($this->once())->method('setArgument')->with('-dNOCACHE')->willReturnSelf(); 107 | $this->assertSame($trait, $trait->setNoCache()); 108 | } 109 | 110 | public function testNoGc() 111 | { 112 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 113 | $trait = $this->getMockForTrait(OtherTrait::class); 114 | $trait->expects($this->once())->method('hasArgument')->with('-dNOGC')->willReturn(false); 115 | $this->assertFalse($trait->isNoGc()); 116 | 117 | $trait->expects($this->once())->method('setArgument')->with('-dNOGC')->willReturnSelf(); 118 | $this->assertSame($trait, $trait->setNoGc()); 119 | } 120 | 121 | public function testNoOuterSave() 122 | { 123 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 124 | $trait = $this->getMockForTrait(OtherTrait::class); 125 | $trait->expects($this->once())->method('hasArgument')->with('-dNOOUTERSAVE')->willReturn(false); 126 | $this->assertFalse($trait->isNoOuterSave()); 127 | 128 | $trait->expects($this->once())->method('setArgument')->with('-dNOOUTERSAVE')->willReturnSelf(); 129 | $this->assertSame($trait, $trait->setNoOuterSave()); 130 | } 131 | 132 | public function testNoSafer() 133 | { 134 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 135 | $trait = $this->getMockForTrait(OtherTrait::class); 136 | $trait->expects($this->once())->method('hasArgument')->with('-dNOSAFER')->willReturn(false); 137 | $this->assertFalse($trait->isNoSafer()); 138 | 139 | $trait->expects($this->once())->method('setArgument')->with('-dNOSAFER')->willReturnSelf(); 140 | $this->assertSame($trait, $trait->setNoSafer()); 141 | } 142 | 143 | public function testSafer() 144 | { 145 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 146 | $trait = $this->getMockForTrait(OtherTrait::class); 147 | $trait->expects($this->once())->method('hasArgument')->with('-dSAFER')->willReturn(false); 148 | $this->assertFalse($trait->isSafer()); 149 | 150 | $trait->expects($this->once())->method('setArgument')->with('-dSAFER')->willReturnSelf(); 151 | $this->assertSame($trait, $trait->setSafer()); 152 | } 153 | 154 | public function testPreBandThresholdTrue() 155 | { 156 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 157 | $trait = $this->getMockForTrait(OtherTrait::class); 158 | $trait->expects($this->exactly(2))->method('getArgumentValue') 159 | ->with('-dPreBandThreshold')->willReturnOnConsecutiveCalls(null, true); 160 | $trait->expects($this->exactly(1))->method('setArgument') 161 | ->with('-dPreBandThreshold=true')->willReturnSelf(); 162 | $this->assertFalse($trait->isPreBandThreshold()); 163 | $this->assertSame($trait, $trait->setPreBandThreshold(true)); 164 | $this->assertTrue($trait->isPreBandThreshold()); 165 | } 166 | 167 | public function testPreBandThresholdFalse() 168 | { 169 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 170 | $trait = $this->getMockForTrait(OtherTrait::class); 171 | $trait->expects($this->exactly(2))->method('getArgumentValue') 172 | ->with('-dPreBandThreshold')->willReturnOnConsecutiveCalls(null, false); 173 | $trait->expects($this->exactly(1))->method('setArgument') 174 | ->with('-dPreBandThreshold=false')->willReturnSelf(); 175 | $this->assertFalse($trait->isPreBandThreshold()); 176 | $this->assertSame($trait, $trait->setPreBandThreshold(false)); 177 | $this->assertFalse($trait->isPreBandThreshold()); 178 | } 179 | 180 | public function testStrict() 181 | { 182 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 183 | $trait = $this->getMockForTrait(OtherTrait::class); 184 | $trait->expects($this->once())->method('hasArgument')->with('-dSTRICT')->willReturn(false); 185 | $this->assertFalse($trait->isStrict()); 186 | 187 | $trait->expects($this->once())->method('setArgument')->with('-dSTRICT')->willReturnSelf(); 188 | $this->assertSame($trait, $trait->setStrict()); 189 | } 190 | 191 | public function testWriteSystemDict() 192 | { 193 | /** @var OtherTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 194 | $trait = $this->getMockForTrait(OtherTrait::class); 195 | $trait->expects($this->once())->method('hasArgument')->with('-dWRITESYSTEMDICT')->willReturn(false); 196 | $this->assertFalse($trait->isWriteSystemDict()); 197 | 198 | $trait->expects($this->once())->method('setArgument')->with('-dWRITESYSTEMDICT')->willReturnSelf(); 199 | $this->assertSame($trait, $trait->setWriteSystemDict()); 200 | } 201 | } 202 | -------------------------------------------------------------------------------- /tests/src/Device/CommandLineParameters/PageTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\CommandLineParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\CommandLineParameters\PageTrait; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The page parameters trait test class. 16 | * 17 | * @package GravityMedia\GhostscriptTest\Device\CommandLineParameters 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\PageTrait::class)] 20 | class PageTraitTest extends TestCase 21 | { 22 | public function testFirstPage() 23 | { 24 | /** @var PageTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 25 | $trait = $this->getMockForTrait(PageTrait::class); 26 | $trait->expects($this->once())->method('getArgumentValue')->with('-dFirstPage')->willReturn(null); 27 | $this->assertNull($trait->getFirstPage()); 28 | 29 | $trait->expects($this->once())->method('setArgument')->with('-dFirstPage=42')->willReturnSelf(); 30 | $this->assertSame($trait, $trait->setFirstPage(42)); 31 | } 32 | 33 | public function testLastPage() 34 | { 35 | /** @var PageTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 36 | $trait = $this->getMockForTrait(PageTrait::class); 37 | $trait->expects($this->once())->method('getArgumentValue')->with('-dLastPage')->willReturn(null); 38 | $this->assertNull($trait->getLastPage()); 39 | 40 | $trait->expects($this->once())->method('setArgument')->with('-dLastPage=42')->willReturnSelf(); 41 | $this->assertSame($trait, $trait->setLastPage(42)); 42 | } 43 | 44 | public function testFixedMedia() 45 | { 46 | /** @var PageTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 47 | $trait = $this->getMockForTrait(PageTrait::class); 48 | $trait->expects($this->once())->method('getArgumentValue')->with('-dFIXEDMEDIA')->willReturn(null); 49 | $this->assertNull($trait->getFixedMedia()); 50 | 51 | $trait->expects($this->once())->method('setArgument')->with('-dFIXEDMEDIA')->willReturnSelf(); 52 | $this->assertSame($trait, $trait->setFixedMedia()); 53 | } 54 | 55 | public function testPDFFitPage() 56 | { 57 | /** @var PageTrait|\PHPUnit_Framework_MockObject_MockObject $trait */ 58 | $trait = $this->getMockForTrait(PageTrait::class); 59 | $trait->expects($this->once())->method('getArgumentValue')->with('-dPDFFitPage')->willReturn(null); 60 | $this->assertNull($trait->getPDFFitPage()); 61 | 62 | $trait->expects($this->once())->method('setArgument')->with('-dPDFFitPage')->willReturnSelf(); 63 | $this->assertSame($trait, $trait->setPDFFitPage()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /tests/src/Device/DeviceTestCase.php: -------------------------------------------------------------------------------- 1 | arguments = new Arguments(); 23 | } 24 | 25 | abstract protected function createDevice(?string $version = null): AbstractDevice; 26 | 27 | protected function getGhostscript(?string $version): Ghostscript|MockObject 28 | { 29 | if ($version === null) { 30 | $ghostscript = new Ghostscript(); 31 | } else { 32 | $ghostscript = $this->createPartialMock(Ghostscript::class, ['getVersion']); 33 | 34 | $ghostscript->expects($this->atLeastOnce()) 35 | ->method('getVersion') 36 | ->willReturn($version); 37 | } 38 | return $ghostscript; 39 | } 40 | 41 | public static function dataVersionsChecks(): array 42 | { 43 | $minVersion = static::getExpectedMinimumVersion(); 44 | return [ 45 | '8.50' => [fn (self $self) => $self->assertVersionCheck( 46 | version: '8.50', 47 | expectedFailure: true, 48 | )], 49 | $minVersion => [fn (self $self) => $self->assertVersionCheck( 50 | version: $minVersion, 51 | expectedFailure: false, 52 | )], 53 | '9.10' => [fn (self $self) => $self->assertVersionCheck( 54 | version: '9.10', 55 | expectedFailure: false, 56 | )], 57 | '9.50' => [fn (self $self) => $self->assertVersionCheck( 58 | version: '9.50', 59 | expectedFailure: false, 60 | )], 61 | '10.00.0' => [fn (self $self) => $self->assertVersionCheck( 62 | version: '10.00.0', // Version from brew (Mac) 63 | expectedFailure: false, 64 | )] 65 | ]; 66 | } 67 | 68 | /** 69 | * @dataProvider dataVersionsChecks 70 | */ 71 | public function testVersionCheck(callable $closure): void 72 | { 73 | $closure($this); 74 | } 75 | 76 | protected function assertVersionCheck( 77 | string $version, 78 | bool $expectedFailure, 79 | ): void 80 | { 81 | if ($expectedFailure) { 82 | $expectedMinimumVersion = static::getExpectedMinimumVersion(); 83 | $this->expectExceptionMessage('Ghostscript version ' . $expectedMinimumVersion . ' or higher is required'); 84 | } 85 | 86 | $device = $this->createDevice($version); 87 | $this->createProcessForVersionTest($device); 88 | } 89 | 90 | protected static function getExpectedMinimumVersion(): string 91 | { 92 | return '9.00'; 93 | } 94 | 95 | protected function createProcessForVersionTest(AbstractDevice $device): Process 96 | { 97 | return $device->createProcess(); 98 | } 99 | 100 | /** 101 | * Returns an OS independent representation of the commandline. 102 | */ 103 | protected function quoteCommandLine(string $commandline): string 104 | { 105 | if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) { 106 | return str_replace('"', '\'', $commandline); 107 | } 108 | 109 | return $commandline; 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /tests/src/Device/DistillerParameters/AdvancedTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\DistillerParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\DistillerParameters\AdvancedTrait; 11 | use GravityMedia\Ghostscript\Enum\PdfSettings; 12 | use PHPUnit\Framework\Attributes\CoversClass; 13 | use PHPUnit\Framework\TestCase; 14 | 15 | /** 16 | * The advanced distiller parameters test class. 17 | * 18 | * @package GravityMedia\GhostscriptTest\Devices\DistillerParameters 19 | */ 20 | #[CoversClass(\GravityMedia\Ghostscript\Device\DistillerParameters\AdvancedTrait::class)] 21 | class AdvancedTraitTest extends TestCase 22 | { 23 | /** 24 | * @param string $pdfSettings 25 | * 26 | * @return AdvancedTrait 27 | */ 28 | protected function createTraitForDefaultValue($pdfSettings) 29 | { 30 | $trait = $this->getMockForTrait(AdvancedTrait::class); 31 | 32 | $trait->expects($this->once()) 33 | ->method('getArgumentValue') 34 | ->willReturn(null); 35 | 36 | $trait->expects($this->once()) 37 | ->method('getPdfSettings') 38 | ->willReturn($pdfSettings); 39 | 40 | return $trait; 41 | } 42 | 43 | /** 44 | * @param null|string $argumentValue 45 | * 46 | * @return AdvancedTrait 47 | */ 48 | protected function createTraitForArgumentValue($argumentValue) 49 | { 50 | $trait = $this->getMockForTrait(AdvancedTrait::class); 51 | 52 | $trait->expects($this->once()) 53 | ->method('getArgumentValue') 54 | ->willReturn($argumentValue); 55 | 56 | // expect the method `setArgument` to be called when the argument value is not null 57 | if (null !== $argumentValue) { 58 | $trait->expects($this->once()) 59 | ->method('setArgument'); 60 | } 61 | 62 | return $trait; 63 | } 64 | 65 | public function testAscii85EncodePagesArgument() 66 | { 67 | $trait = $this->createTraitForArgumentValue(null); 68 | $this->assertFalse($trait->isAscii85EncodePages()); 69 | 70 | $trait = $this->createTraitForArgumentValue(true); 71 | $this->assertTrue($trait->setAscii85EncodePages(true)->isAscii85EncodePages()); 72 | } 73 | 74 | public function testAutoPositionEpsFilesArgument() 75 | { 76 | $trait = $this->createTraitForArgumentValue(null); 77 | $this->assertFalse($trait->isAutoPositionEpsFiles()); 78 | 79 | $trait = $this->createTraitForArgumentValue(true); 80 | $this->assertTrue($trait->setAutoPositionEpsFiles(true)->isAutoPositionEpsFiles()); 81 | } 82 | 83 | /** 84 | * @dataProvider providePdfSettingsForCreateJobTicket 85 | * 86 | * @param bool $createJobTicket 87 | * @param string $pdfSettings 88 | */ 89 | public function testCreateJobTicketArgument($createJobTicket, $pdfSettings) 90 | { 91 | $trait = $this->createTraitForDefaultValue($pdfSettings); 92 | $this->assertSame($createJobTicket, $trait->isCreateJobTicket()); 93 | 94 | $trait = $this->createTraitForArgumentValue($createJobTicket); 95 | $this->assertSame($createJobTicket, $trait->setCreateJobTicket($createJobTicket)->isCreateJobTicket()); 96 | } 97 | 98 | /** 99 | * @return array 100 | */ 101 | public static function providePdfSettingsForCreateJobTicket() 102 | { 103 | return [ 104 | [false, PdfSettings::__DEFAULT], 105 | [false, PdfSettings::SCREEN], 106 | [false, PdfSettings::EBOOK], 107 | [true, PdfSettings::PRINTER], 108 | [true, PdfSettings::PREPRESS] 109 | ]; 110 | } 111 | 112 | public function testDetectBlendsArgument() 113 | { 114 | $trait = $this->createTraitForArgumentValue(null); 115 | $this->assertTrue($trait->isDetectBlends()); 116 | 117 | $trait = $this->createTraitForArgumentValue(false); 118 | $this->assertFalse($trait->setDetectBlends(false)->isDetectBlends()); 119 | } 120 | 121 | public function testEmitDscWarningsArgument() 122 | { 123 | $trait = $this->createTraitForArgumentValue(null); 124 | $this->assertFalse($trait->isEmitDscWarnings()); 125 | 126 | $trait = $this->createTraitForArgumentValue(true); 127 | $this->assertTrue($trait->setEmitDscWarnings(true)->isEmitDscWarnings()); 128 | } 129 | 130 | public function testLockDistillerParamsArgument() 131 | { 132 | $trait = $this->createTraitForArgumentValue(null); 133 | $this->assertFalse($trait->isLockDistillerParams()); 134 | 135 | $trait = $this->createTraitForArgumentValue(true); 136 | $this->assertTrue($trait->setLockDistillerParams(true)->isLockDistillerParams()); 137 | } 138 | 139 | public function testOpmArgument() 140 | { 141 | $trait = $this->createTraitForArgumentValue(null); 142 | $this->assertSame(1, $trait->getOpm()); 143 | 144 | $trait = $this->createTraitForArgumentValue(2); 145 | $this->assertSame(2, $trait->setOpm(2)->getOpm()); 146 | } 147 | 148 | public function testParseDscCommentsArgument() 149 | { 150 | $trait = $this->createTraitForArgumentValue(null); 151 | $this->assertTrue($trait->isParseDscComments()); 152 | 153 | $trait = $this->createTraitForArgumentValue(false); 154 | $this->assertFalse($trait->setParseDscComments(false)->isParseDscComments()); 155 | } 156 | 157 | public function testParseDscCommentsForDocInfoArgument() 158 | { 159 | $trait = $this->createTraitForArgumentValue(null); 160 | $this->assertTrue($trait->isParseDscCommentsForDocInfo()); 161 | 162 | $trait = $this->createTraitForArgumentValue(false); 163 | $this->assertFalse($trait->setParseDscCommentsForDocInfo(false)->isParseDscCommentsForDocInfo()); 164 | } 165 | 166 | public function testPreserveCopyPageArgument() 167 | { 168 | $trait = $this->createTraitForArgumentValue(null); 169 | $this->assertTrue($trait->isPreserveCopyPage()); 170 | 171 | $trait = $this->createTraitForArgumentValue(false); 172 | $this->assertFalse($trait->setPreserveCopyPage(false)->isPreserveCopyPage()); 173 | } 174 | 175 | public function testPreserveEpsInfoArgument() 176 | { 177 | $trait = $this->createTraitForArgumentValue(null); 178 | $this->assertTrue($trait->isPreserveEpsInfo()); 179 | 180 | $trait = $this->createTraitForArgumentValue(false); 181 | $this->assertFalse($trait->setPreserveEpsInfo(false)->isPreserveEpsInfo()); 182 | } 183 | 184 | /** 185 | * @dataProvider providePdfSettingsForPreserveOpiComments 186 | * 187 | * @param bool $preserveOpiComments 188 | * @param string $pdfSettings 189 | */ 190 | public function testPreserveOpiCommentsArgument($preserveOpiComments, $pdfSettings) 191 | { 192 | $trait = $this->createTraitForDefaultValue($pdfSettings); 193 | $this->assertSame($preserveOpiComments, $trait->isPreserveOpiComments()); 194 | 195 | $trait = $this->createTraitForArgumentValue($preserveOpiComments); 196 | $this->assertSame( 197 | $preserveOpiComments, 198 | $trait->setPreserveOpiComments($preserveOpiComments)->isPreserveOpiComments() 199 | ); 200 | } 201 | 202 | /** 203 | * @return array 204 | */ 205 | public static function providePdfSettingsForPreserveOpiComments() 206 | { 207 | return [ 208 | [false, PdfSettings::__DEFAULT], 209 | [false, PdfSettings::SCREEN], 210 | [false, PdfSettings::EBOOK], 211 | [true, PdfSettings::PRINTER], 212 | [true, PdfSettings::PREPRESS] 213 | ]; 214 | } 215 | 216 | public function testUsePrologueArgument() 217 | { 218 | $trait = $this->createTraitForArgumentValue(null); 219 | $this->assertFalse($trait->isUsePrologue()); 220 | 221 | $trait = $this->createTraitForArgumentValue(true); 222 | $this->assertTrue($trait->setUsePrologue(true)->isUsePrologue()); 223 | } 224 | } 225 | -------------------------------------------------------------------------------- /tests/src/Device/DistillerParameters/FontTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\DistillerParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\DistillerParameters\FontTrait; 11 | use GravityMedia\Ghostscript\Enum\CannotEmbedFontPolicy; 12 | use GravityMedia\Ghostscript\Enum\PdfSettings; 13 | use PHPUnit\Framework\Attributes\CoversClass; 14 | use PHPUnit\Framework\Attributes\UsesClass; 15 | use PHPUnit\Framework\TestCase; 16 | 17 | /** 18 | * The font distiller parameters test class. 19 | * 20 | * @package GravityMedia\GhostscriptTest\Devices\DistillerParameters 21 | */ 22 | #[CoversClass(\GravityMedia\Ghostscript\Device\DistillerParameters\FontTrait::class)] 23 | #[UsesClass(\GravityMedia\Ghostscript\Enum\CannotEmbedFontPolicy::class)] 24 | class FontTraitTest extends TestCase 25 | { 26 | /** 27 | * @param string $pdfSettings 28 | * 29 | * @return FontTrait 30 | */ 31 | protected function createTraitForDefaultValue($pdfSettings) 32 | { 33 | $trait = $this->getMockForTrait(FontTrait::class); 34 | 35 | $trait->expects($this->once()) 36 | ->method('getArgumentValue') 37 | ->willReturn(null); 38 | 39 | $trait->expects($this->once()) 40 | ->method('getPdfSettings') 41 | ->willReturn($pdfSettings); 42 | 43 | return $trait; 44 | } 45 | 46 | /** 47 | * @param null|string $argumentValue 48 | * 49 | * @return FontTrait 50 | */ 51 | protected function createTraitForArgumentValue($argumentValue) 52 | { 53 | $trait = $this->getMockForTrait(FontTrait::class); 54 | 55 | $trait->expects($this->once()) 56 | ->method('getArgumentValue') 57 | ->willReturn($argumentValue); 58 | 59 | // expect the method `setArgument` to be called when the argument value is not null 60 | if (null !== $argumentValue) { 61 | $trait->expects($this->once()) 62 | ->method('setArgument'); 63 | } 64 | 65 | return $trait; 66 | } 67 | 68 | /** 69 | * @dataProvider providePdfSettingsForCannotEmbedFontPolicy 70 | * 71 | * @param string $cannotEmbedFontPolicy 72 | * @param string $pdfSettings 73 | */ 74 | public function testCannotEmbedFontPolicyArgument($cannotEmbedFontPolicy, $pdfSettings) 75 | { 76 | $trait = $this->createTraitForDefaultValue($pdfSettings); 77 | $this->assertSame($cannotEmbedFontPolicy, $trait->getCannotEmbedFontPolicy()); 78 | 79 | $trait = $this->createTraitForArgumentValue('/' . $cannotEmbedFontPolicy); 80 | $this->assertSame( 81 | $cannotEmbedFontPolicy, 82 | $trait->setCannotEmbedFontPolicy($cannotEmbedFontPolicy)->getCannotEmbedFontPolicy() 83 | ); 84 | } 85 | 86 | /** 87 | * @return array 88 | */ 89 | public static function providePdfSettingsForCannotEmbedFontPolicy() 90 | { 91 | return [ 92 | [CannotEmbedFontPolicy::WARNING, PdfSettings::__DEFAULT], 93 | [CannotEmbedFontPolicy::WARNING, PdfSettings::SCREEN], 94 | [CannotEmbedFontPolicy::WARNING, PdfSettings::EBOOK], 95 | [CannotEmbedFontPolicy::WARNING, PdfSettings::PRINTER], 96 | [CannotEmbedFontPolicy::ERROR, PdfSettings::PREPRESS] 97 | ]; 98 | } 99 | 100 | /** 101 | * @expectedException \InvalidArgumentException 102 | */ 103 | public function testCannotEmbedFontPolicyArgumentThrowsException() 104 | { 105 | $this->expectExceptionMessage('Invalid cannot embed font policy argument'); 106 | 107 | /** @var FontTrait $trait */ 108 | $trait = $this->getMockForTrait(FontTrait::class); 109 | 110 | $trait->setCannotEmbedFontPolicy('/Foo'); 111 | } 112 | 113 | /** 114 | * @dataProvider providePdfSettingsForEmbedAllFonts 115 | * 116 | * @param bool $embedAllFonts 117 | * @param string $pdfSettings 118 | */ 119 | public function testEmbedAllFontsArgument($embedAllFonts, $pdfSettings) 120 | { 121 | $trait = $this->createTraitForDefaultValue($pdfSettings); 122 | $this->assertSame($embedAllFonts, $trait->isEmbedAllFonts()); 123 | 124 | $trait = $this->createTraitForArgumentValue($embedAllFonts); 125 | $this->assertSame($embedAllFonts, $trait->setEmbedAllFonts($embedAllFonts)->isEmbedAllFonts()); 126 | } 127 | 128 | /** 129 | * @return array 130 | */ 131 | public static function providePdfSettingsForEmbedAllFonts() 132 | { 133 | return [ 134 | [true, PdfSettings::__DEFAULT], 135 | [false, PdfSettings::SCREEN], 136 | [true, PdfSettings::EBOOK], 137 | [true, PdfSettings::PRINTER], 138 | [true, PdfSettings::PREPRESS] 139 | ]; 140 | } 141 | 142 | public function testMaxSubsetPctArgument() 143 | { 144 | $trait = $this->createTraitForArgumentValue(null); 145 | $this->assertSame(100, $trait->getMaxSubsetPct()); 146 | 147 | $trait = $this->createTraitForArgumentValue(66); 148 | $this->assertSame(66, $trait->setMaxSubsetPct(66)->getMaxSubsetPct()); 149 | } 150 | 151 | public function testSubsetFontsArgument() 152 | { 153 | $trait = $this->createTraitForArgumentValue(null); 154 | $this->assertTrue($trait->isSubsetFonts()); 155 | 156 | $trait = $this->createTraitForArgumentValue(false); 157 | $this->assertFalse($trait->setSubsetFonts(false)->isSubsetFonts()); 158 | } 159 | } 160 | -------------------------------------------------------------------------------- /tests/src/Device/DistillerParameters/MonoImageCompressionTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\DistillerParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\DistillerParameters\MonoImageCompressionTrait; 11 | use GravityMedia\Ghostscript\Enum\ImageDownsampleType; 12 | use GravityMedia\Ghostscript\Enum\MonoImageFilter; 13 | use GravityMedia\Ghostscript\Enum\PdfSettings; 14 | use PHPUnit\Framework\Attributes\CoversClass; 15 | use PHPUnit\Framework\Attributes\UsesClass; 16 | use PHPUnit\Framework\TestCase; 17 | 18 | /** 19 | * The monochrome image compression distiller parameters test class. 20 | * 21 | * @package GravityMedia\GhostscriptTest\Devices\DistillerParameters 22 | */ 23 | #[CoversClass(\GravityMedia\Ghostscript\Device\DistillerParameters\MonoImageCompressionTrait::class)] 24 | #[UsesClass(\GravityMedia\Ghostscript\Enum\MonoImageFilter::class)] 25 | #[UsesClass(\GravityMedia\Ghostscript\Enum\ImageDownsampleType::class)] 26 | class MonoImageCompressionTraitTest extends TestCase 27 | { 28 | /** 29 | * @param string $pdfSettings 30 | * 31 | * @return MonoImageCompressionTrait 32 | */ 33 | protected function createTraitForDefaultValue($pdfSettings) 34 | { 35 | $trait = $this->getMockForTrait(MonoImageCompressionTrait::class); 36 | 37 | $trait->expects($this->once()) 38 | ->method('getArgumentValue') 39 | ->willReturn(null); 40 | 41 | $trait->expects($this->once()) 42 | ->method('getPdfSettings') 43 | ->willReturn($pdfSettings); 44 | 45 | return $trait; 46 | } 47 | 48 | /** 49 | * @param null|string $argumentValue 50 | * 51 | * @return MonoImageCompressionTrait 52 | */ 53 | protected function createTraitForArgumentValue($argumentValue) 54 | { 55 | $trait = $this->getMockForTrait(MonoImageCompressionTrait::class); 56 | 57 | $trait->expects($this->once()) 58 | ->method('getArgumentValue') 59 | ->willReturn($argumentValue); 60 | 61 | // expect the method `setArgument` to be called when the argument value is not null 62 | if (null !== $argumentValue) { 63 | $trait->expects($this->once()) 64 | ->method('setArgument'); 65 | } 66 | 67 | return $trait; 68 | } 69 | 70 | public function testAntiAliasMonoImagesArgument() 71 | { 72 | $trait = $this->createTraitForArgumentValue(null); 73 | $this->assertFalse($trait->isAntiAliasMonoImages()); 74 | 75 | $trait = $this->createTraitForArgumentValue(true); 76 | $this->assertTrue($trait->setAntiAliasMonoImages(true)->isAntiAliasMonoImages()); 77 | } 78 | 79 | public function testMonoImageDepthArgument() 80 | { 81 | $trait = $this->createTraitForArgumentValue(null); 82 | $this->assertSame(-1, $trait->getMonoImageDepth()); 83 | 84 | $trait = $this->createTraitForArgumentValue(8); 85 | $this->assertSame(8, $trait->setMonoImageDepth(8)->getMonoImageDepth()); 86 | } 87 | 88 | public function testMonoImageDownsampleThresholdArgument() 89 | { 90 | $trait = $this->createTraitForArgumentValue(null); 91 | $this->assertSame(1.5, $trait->getMonoImageDownsampleThreshold()); 92 | 93 | $trait = $this->createTraitForArgumentValue(1.0); 94 | $this->assertSame(1.0, $trait->setMonoImageDownsampleThreshold(1.0)->getMonoImageDownsampleThreshold()); 95 | } 96 | 97 | /** 98 | * @dataProvider providePdfSettingsForMonoImageDownsampleType 99 | * 100 | * @param string $monoImageDownsampleType 101 | * @param string $pdfSettings 102 | */ 103 | public function testMonoImageDownsampleTypeArgument($monoImageDownsampleType, $pdfSettings) 104 | { 105 | $trait = $this->createTraitForDefaultValue($pdfSettings); 106 | $this->assertSame($monoImageDownsampleType, $trait->getMonoImageDownsampleType()); 107 | 108 | $trait = $this->createTraitForArgumentValue('/' . $monoImageDownsampleType); 109 | $this->assertSame( 110 | $monoImageDownsampleType, 111 | $trait->setMonoImageDownsampleType($monoImageDownsampleType)->getMonoImageDownsampleType() 112 | ); 113 | } 114 | 115 | /** 116 | * @return array 117 | */ 118 | public static function providePdfSettingsForMonoImageDownsampleType() 119 | { 120 | return [ 121 | [ImageDownsampleType::SUBSAMPLE, PdfSettings::__DEFAULT], 122 | [ImageDownsampleType::SUBSAMPLE, PdfSettings::SCREEN], 123 | [ImageDownsampleType::SUBSAMPLE, PdfSettings::EBOOK], 124 | [ImageDownsampleType::SUBSAMPLE, PdfSettings::PRINTER], 125 | [ImageDownsampleType::BICUBIC, PdfSettings::PREPRESS] 126 | ]; 127 | } 128 | 129 | /** 130 | * @expectedException \InvalidArgumentException 131 | */ 132 | public function testMonoImageDownsampleTypeArgumentThrowsException() 133 | { 134 | $this->expectExceptionMessage('Invalid monochrome image downsample type argument'); 135 | 136 | /** @var MonoImageCompressionTrait $trait */ 137 | $trait = $this->getMockForTrait(MonoImageCompressionTrait::class); 138 | 139 | $trait->setMonoImageDownsampleType('/Foo'); 140 | } 141 | 142 | public function testMonoImageFilterFallbackArgument() 143 | { 144 | $trait = $this->createTraitForArgumentValue(null); 145 | $this->assertSame(MonoImageFilter::CCITT_FAX_ENCODE, $trait->getMonoImageFilter()); 146 | } 147 | 148 | /** 149 | * @dataProvider providePdfSettingsForMonoImageFilter 150 | * 151 | * @param string $transferFunctionInfo 152 | */ 153 | public function testMonoImageFilterArgument($transferFunctionInfo) 154 | { 155 | $trait = $this->createTraitForArgumentValue('/' . $transferFunctionInfo); 156 | $this->assertSame( 157 | $transferFunctionInfo, 158 | $trait->setMonoImageFilter($transferFunctionInfo)->getMonoImageFilter() 159 | ); 160 | } 161 | 162 | /** 163 | * @return array 164 | */ 165 | public static function providePdfSettingsForMonoImageFilter() 166 | { 167 | return [ 168 | [MonoImageFilter::CCITT_FAX_ENCODE], 169 | [MonoImageFilter::FLATE_ENCODE], 170 | [MonoImageFilter::RUN_LENGTH_ENCODE] 171 | ]; 172 | } 173 | 174 | /** 175 | * @expectedException \InvalidArgumentException 176 | */ 177 | public function testMonoImageFilterArgumentThrowsException() 178 | { 179 | $this->expectExceptionMessage('Invalid monochrome image filter argument'); 180 | 181 | /** @var MonoImageCompressionTrait $trait */ 182 | $trait = $this->getMockForTrait(MonoImageCompressionTrait::class); 183 | 184 | $trait->setMonoImageFilter('/Foo'); 185 | } 186 | 187 | /** 188 | * @dataProvider providePdfSettingsForMonoImageResolution 189 | * 190 | * @param int $monoImageResolution 191 | * @param string $pdfSettings 192 | */ 193 | public function testMonoImageResolutionArgument($monoImageResolution, $pdfSettings) 194 | { 195 | $trait = $this->createTraitForDefaultValue($pdfSettings); 196 | $this->assertSame($monoImageResolution, $trait->getMonoImageResolution()); 197 | 198 | $trait = $this->createTraitForArgumentValue($monoImageResolution); 199 | $this->assertSame( 200 | $monoImageResolution, 201 | $trait->setMonoImageResolution($monoImageResolution)->getMonoImageResolution() 202 | ); 203 | } 204 | 205 | /** 206 | * @return array 207 | */ 208 | public static function providePdfSettingsForMonoImageResolution() 209 | { 210 | return [ 211 | [300, PdfSettings::__DEFAULT], 212 | [300, PdfSettings::SCREEN], 213 | [300, PdfSettings::EBOOK], 214 | [1200, PdfSettings::PRINTER], 215 | [1200, PdfSettings::PREPRESS] 216 | ]; 217 | } 218 | 219 | /** 220 | * @dataProvider providePdfSettingsForDownsampleMonoImages 221 | * 222 | * @param bool $downsampleMonoImages 223 | * @param string $pdfSettings 224 | */ 225 | public function testDownsampleMonoImagesArgument($downsampleMonoImages, $pdfSettings) 226 | { 227 | $trait = $this->createTraitForDefaultValue($pdfSettings); 228 | $this->assertSame($downsampleMonoImages, $trait->isDownsampleMonoImages()); 229 | 230 | $trait = $this->createTraitForArgumentValue($downsampleMonoImages); 231 | $this->assertSame( 232 | $downsampleMonoImages, 233 | $trait->setDownsampleMonoImages($downsampleMonoImages)->isDownsampleMonoImages() 234 | ); 235 | } 236 | 237 | /** 238 | * @return array 239 | */ 240 | public static function providePdfSettingsForDownsampleMonoImages() 241 | { 242 | return [ 243 | [false, PdfSettings::__DEFAULT], 244 | [true, PdfSettings::SCREEN], 245 | [true, PdfSettings::EBOOK], 246 | [false, PdfSettings::PRINTER], 247 | [false, PdfSettings::PREPRESS] 248 | ]; 249 | } 250 | 251 | public function testEncodeMonoImagesArgument() 252 | { 253 | $trait = $this->createTraitForArgumentValue(null); 254 | $this->assertTrue($trait->isEncodeMonoImages()); 255 | 256 | $trait = $this->createTraitForArgumentValue(false); 257 | $this->assertFalse($trait->setEncodeMonoImages(false)->isEncodeMonoImages()); 258 | } 259 | } 260 | -------------------------------------------------------------------------------- /tests/src/Device/DistillerParameters/PageCompressionTraitTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device\DistillerParameters; 9 | 10 | use GravityMedia\Ghostscript\Device\DistillerParameters\PageCompressionTrait; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The page compression distiller parameters test class. 16 | * 17 | * @package GravityMedia\GhostscriptTest\Devices\DistillerParameters 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Device\DistillerParameters\PageCompressionTrait::class)] 20 | class PageCompressionTraitTest extends TestCase 21 | { 22 | /** 23 | * @param null|string $argumentValue 24 | * 25 | * @return PageCompressionTrait 26 | */ 27 | protected function createTraitForArgumentValue($argumentValue) 28 | { 29 | $trait = $this->getMockForTrait(PageCompressionTrait::class); 30 | 31 | $trait->expects($this->once()) 32 | ->method('getArgumentValue') 33 | ->willReturn($argumentValue); 34 | 35 | // expect the method `setArgument` to be called when the argument value is not null 36 | if (null !== $argumentValue) { 37 | $trait->expects($this->once()) 38 | ->method('setArgument'); 39 | } 40 | 41 | return $trait; 42 | } 43 | 44 | public function testCompressPagesArgument() 45 | { 46 | $trait = $this->createTraitForArgumentValue(null); 47 | $this->assertTrue($trait->isCompressPages()); 48 | 49 | $trait = $this->createTraitForArgumentValue(false); 50 | $this->assertFalse($trait->setCompressPages(false)->isCompressPages()); 51 | } 52 | 53 | public function testLzwEncodePagesArgument() 54 | { 55 | $trait = $this->createTraitForArgumentValue(null); 56 | $this->assertFalse($trait->isLzwEncodePages()); 57 | 58 | $trait = $this->createTraitForArgumentValue(true); 59 | $this->assertTrue($trait->setLzwEncodePages(true)->isLzwEncodePages()); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /tests/src/Device/InkcovTest.php: -------------------------------------------------------------------------------- 1 | getGhostscript($version), $this->arguments); 28 | } 29 | 30 | public function testDeviceCreation() 31 | { 32 | $device = $this->createDevice(); 33 | 34 | $this->assertInstanceOf(Inkcov::class, $device); 35 | $this->assertInstanceOf(Argument::class, $this->arguments->getArgument('-sDEVICE')); 36 | $this->assertEquals('inkcov', $this->arguments->getArgument('-sDEVICE')->getValue()); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /tests/src/Device/NoDisplayTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device; 9 | 10 | use GravityMedia\Ghostscript\Device\AbstractDevice; 11 | use GravityMedia\Ghostscript\Device\NoDisplay; 12 | use GravityMedia\Ghostscript\Process\Argument; 13 | use PHPUnit\Framework\Attributes\CoversClass; 14 | use PHPUnit\Framework\Attributes\UsesClass; 15 | 16 | /** 17 | * The no display device test class. 18 | * 19 | * @package GravityMedia\GhostscriptTest\Devices 20 | */ 21 | #[CoversClass(\GravityMedia\Ghostscript\Device\NoDisplay::class)] 22 | #[UsesClass(\GravityMedia\Ghostscript\Ghostscript::class)] 23 | #[UsesClass(\GravityMedia\Ghostscript\Device\AbstractDevice::class)] 24 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 25 | #[UsesClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 26 | class NoDisplayTest extends DeviceTestCase 27 | { 28 | protected function createDevice(?string $version = null): AbstractDevice 29 | { 30 | $ghostscript = $this->getGhostscript($version); 31 | 32 | return new NoDisplay($ghostscript, $this->arguments); 33 | } 34 | 35 | public function testDeviceCreation() 36 | { 37 | $device = $this->createDevice(); 38 | 39 | $this->assertInstanceOf(NoDisplay::class, $device); 40 | $this->assertInstanceOf(Argument::class, $this->arguments->getArgument('-dNODISPLAY')); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /tests/src/Device/PdfInfoTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device; 9 | 10 | use GravityMedia\Ghostscript\Device\AbstractDevice; 11 | use GravityMedia\Ghostscript\Device\PdfInfo; 12 | use GravityMedia\Ghostscript\Process\Arguments; 13 | use Symfony\Component\Process\Process; 14 | use PHPUnit\Framework\Attributes\CoversClass; 15 | use PHPUnit\Framework\Attributes\UsesClass; 16 | 17 | /** 18 | * The pdf info device test class. 19 | * 20 | * @package GravityMedia\GhostscriptTest\Devices 21 | */ 22 | #[CoversClass(\GravityMedia\Ghostscript\Device\PdfInfo::class)] 23 | #[UsesClass(\GravityMedia\Ghostscript\Ghostscript::class)] 24 | #[UsesClass(\GravityMedia\Ghostscript\Input::class)] 25 | #[UsesClass(\GravityMedia\Ghostscript\Device\AbstractDevice::class)] 26 | #[UsesClass(\GravityMedia\Ghostscript\Device\NoDisplay::class)] 27 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 28 | #[UsesClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 29 | class PdfInfoTest extends DeviceTestCase 30 | { 31 | const PDF_PATH = __DIR__ . '/../../data/pdf_info.ps'; 32 | 33 | protected function createDevice(?string $version = null): PdfInfo 34 | { 35 | $ghostscript = $this->getGhostscript($version); 36 | $arguments = new Arguments(); 37 | 38 | return new PdfInfo($ghostscript, $arguments, self::PDF_PATH); 39 | } 40 | 41 | public function testDeviceCreation() 42 | { 43 | $device = $this->createDevice(); 44 | $field = new \ReflectionProperty(PdfInfo::class, 'pdfInfoPath'); 45 | $field->setAccessible(true); 46 | $this->assertEquals(self::PDF_PATH, $field->getValue($device)); 47 | } 48 | 49 | public function testProcessCreation() 50 | { 51 | $inputFile = __DIR__ . '/../../data/input.pdf'; 52 | $pdfInfoPath = self::PDF_PATH; 53 | $device = $this->createDevice(); 54 | $process = $device->createProcess($inputFile); 55 | 56 | $expectedCommandLine = "'gs' '-dNODISPLAY' '-sFile=$inputFile' '-f' '$pdfInfoPath'"; 57 | $this->assertEquals($expectedCommandLine, $this->quoteCommandLine($process->getCommandLine())); 58 | } 59 | 60 | /** 61 | * @expectedException \RuntimeException 62 | */ 63 | public function testProcessCreationThrowsExceptionOnMissingInputFile() 64 | { 65 | $this->expectExceptionMessage('Input file does not exist'); 66 | 67 | $device = $this->createDevice(); 68 | $device->createProcess(); 69 | } 70 | 71 | protected function createProcessForVersionTest(AbstractDevice $device): Process 72 | { 73 | $inputFile = __DIR__ . '/../../data/input.pdf'; 74 | 75 | return $device->createProcess($inputFile); 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /tests/src/Device/PdfWriteTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Device; 9 | 10 | use GravityMedia\Ghostscript\Device\PdfWrite; 11 | use GravityMedia\Ghostscript\Enum\PdfSettings; 12 | use GravityMedia\Ghostscript\Enum\ProcessColorModel; 13 | use PHPUnit\Framework\Attributes\CoversClass; 14 | use PHPUnit\Framework\Attributes\UsesClass; 15 | 16 | /** 17 | * The PDF write device test class. 18 | * 19 | * @package GravityMedia\GhostscriptTest\Devices 20 | */ 21 | #[CoversClass(\GravityMedia\Ghostscript\Device\PdfWrite::class)] 22 | #[UsesClass(\GravityMedia\Ghostscript\Ghostscript::class)] 23 | #[UsesClass(\GravityMedia\Ghostscript\Input::class)] 24 | #[UsesClass(\GravityMedia\Ghostscript\Enum\PdfSettings::class)] 25 | #[UsesClass(\GravityMedia\Ghostscript\Enum\ProcessColorModel::class)] 26 | #[UsesClass(\GravityMedia\Ghostscript\Device\AbstractDevice::class)] 27 | #[UsesClass(\GravityMedia\Ghostscript\Device\DistillerParametersTrait::class)] 28 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 29 | #[UsesClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 30 | class PdfWriteTest extends DeviceTestCase 31 | { 32 | protected function createDevice(?string $version = null): PdfWrite 33 | { 34 | return new PdfWrite($this->getGhostscript($version), $this->arguments); 35 | } 36 | 37 | public function testDeviceCreation() 38 | { 39 | $this->assertInstanceOf('GravityMedia\Ghostscript\Device\PdfWrite', $this->createDevice()); 40 | } 41 | 42 | public function testOutputFileArgument() 43 | { 44 | $device = $this->createDevice(); 45 | $outputFile = '/path/to/output/file.pdf'; 46 | 47 | $this->assertNull($device->getOutputFile()); 48 | $this->assertSame($outputFile, $device->setOutputFile($outputFile)->getOutputFile()); 49 | } 50 | 51 | /** 52 | * @dataProvider providePdfSettings 53 | * 54 | * @param string $pdfSettings 55 | */ 56 | public function testPdfSettingsArgument($pdfSettings) 57 | { 58 | $device = $this->createDevice(); 59 | 60 | $this->assertSame(PdfSettings::__DEFAULT, $device->getPdfSettings()); 61 | $this->assertSame($pdfSettings, $device->setPdfSettings($pdfSettings)->getPdfSettings()); 62 | } 63 | 64 | /** 65 | * @return array 66 | */ 67 | public static function providePdfSettings() 68 | { 69 | return [ 70 | [PdfSettings::__DEFAULT], 71 | [PdfSettings::SCREEN], 72 | [PdfSettings::EBOOK], 73 | [PdfSettings::PRINTER], 74 | [PdfSettings::PREPRESS] 75 | ]; 76 | } 77 | 78 | /** 79 | * @expectedException \InvalidArgumentException 80 | */ 81 | public function testPdfSettingsSetterThrowsExceptionOnInvalidArgument() 82 | { 83 | $this->expectExceptionMessage('Invalid PDF settings argument'); 84 | 85 | $this->createDevice()->setPdfSettings('/foo'); 86 | } 87 | 88 | /** 89 | * @dataProvider provideProcessColorModel 90 | * 91 | * @param string $processColorModel 92 | */ 93 | public function testProcessColorModelArgument($processColorModel) 94 | { 95 | $device = $this->createDevice(); 96 | $this->assertSame($processColorModel, $device->setProcessColorModel($processColorModel)->getProcessColorModel()); 97 | } 98 | 99 | /** 100 | * @return array 101 | */ 102 | public static function provideProcessColorModel(): array 103 | { 104 | return [ 105 | [ProcessColorModel::DEVICE_RGB], 106 | [ProcessColorModel::DEVICE_CMYK], 107 | [ProcessColorModel::DEVICE_GRAY] 108 | ]; 109 | } 110 | 111 | /** 112 | * @expectedException \InvalidArgumentException 113 | */ 114 | public function testProcessColorModelSetterThrowsExceptionOnInvalidArgument() 115 | { 116 | $this->expectExceptionMessage('Invalid process color model argument'); 117 | $this->createDevice()->setProcessColorModel('/foo'); 118 | } 119 | 120 | public static function dataProcessCreation(): array 121 | { 122 | return [ 123 | [fn (self $self) => $self->assertProcessCreation( 124 | version: '9.00', 125 | expectSetPDFWrite: true, 126 | )], 127 | [fn (self $self) => $self->assertProcessCreation( 128 | version: '9.10', 129 | expectSetPDFWrite: true, 130 | )], 131 | [fn (self $self) => $self->assertProcessCreation( 132 | version: '9.50', 133 | expectSetPDFWrite: false, 134 | )], 135 | [fn (self $self) => $self->assertProcessCreation( 136 | version: '10.00.0', 137 | expectSetPDFWrite: false, 138 | )] 139 | ]; 140 | } 141 | 142 | /** 143 | * @dataProvider dataProcessCreation 144 | */ 145 | public function testProcessCreation(callable $closure): void 146 | { 147 | $closure($this); 148 | } 149 | 150 | protected function assertProcessCreation( 151 | string $version, 152 | bool $expectSetPDFWrite, 153 | ): void 154 | { 155 | $process = $this->createDevice($version)->createProcess(); 156 | 157 | $command = "'gs' '-sDEVICE=pdfwrite' '-dPDFSETTINGS=/default'"; 158 | $this->assertEquals( 159 | $expectSetPDFWrite ? "{$command} '-c' '.setpdfwrite'" : $command, 160 | $this->quoteCommandLine($process->getCommandLine()) 161 | ); 162 | } 163 | } 164 | -------------------------------------------------------------------------------- /tests/src/Enum/AutoRotatePagesTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\AutoRotatePages; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The auto rotate pages enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\AutoRotatePages::class)] 20 | class AutoRotatePagesTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | AutoRotatePages::NONE, 26 | AutoRotatePages::ALL, 27 | AutoRotatePages::PAGE_BY_PAGE 28 | ]; 29 | 30 | $this->assertEquals($values, AutoRotatePages::values()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/Enum/BindingTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\Binding; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The binding enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\Binding::class)] 20 | class BindingTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | Binding::LEFT, 26 | Binding::RIGHT 27 | ]; 28 | 29 | $this->assertEquals($values, Binding::values()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/Enum/CannotEmbedFontPolicyTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\CannotEmbedFontPolicy; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The cannot embed font policy enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\CannotEmbedFontPolicy::class)] 20 | class CannotEmbedFontPolicyTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | CannotEmbedFontPolicy::OK, 26 | CannotEmbedFontPolicy::WARNING, 27 | CannotEmbedFontPolicy::ERROR 28 | ]; 29 | 30 | $this->assertEquals($values, CannotEmbedFontPolicy::values()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/Enum/ColorAndGrayImageFilterTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\ColorAndGrayImageFilter; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The color and grayscale image filter enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\ColorAndGrayImageFilter::class)] 20 | class ColorAndGrayImageFilterTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | ColorAndGrayImageFilter::DCT_ENCODE, 26 | ColorAndGrayImageFilter::FLATE_ENCODE 27 | ]; 28 | 29 | $this->assertEquals($values, ColorAndGrayImageFilter::values()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/Enum/ColorConversionStrategyTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\ColorConversionStrategy; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The color conversion strategy enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\ColorConversionStrategy::class)] 20 | class ColorConversionStrategyTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | ColorConversionStrategy::LEAVE_COLOR_UNCHANGED, 26 | ColorConversionStrategy::USE_DEVICE_INDEPENDENT_COLOR, 27 | ColorConversionStrategy::GRAY, 28 | ColorConversionStrategy::SRGB, 29 | ColorConversionStrategy::CMYK 30 | ]; 31 | 32 | $this->assertEquals($values, ColorConversionStrategy::values()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/src/Enum/DefaultRenderingIntentTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\DefaultRenderingIntent; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The default rendering intent enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\DefaultRenderingIntent::class)] 20 | class DefaultRenderingIntentTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | DefaultRenderingIntent::__DEFAULT, 26 | DefaultRenderingIntent::PERCEPTUAL, 27 | DefaultRenderingIntent::SATURATION, 28 | DefaultRenderingIntent::RELATIVE_COLORIMETRIC, 29 | DefaultRenderingIntent::ABSOLUTE_COLORIMETRIC 30 | ]; 31 | 32 | $this->assertEquals($values, DefaultRenderingIntent::values()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/src/Enum/ImageDownsampleTypeTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\ImageDownsampleType; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The image downsample type enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\ImageDownsampleType::class)] 20 | class ImageDownsampleTypeTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | ImageDownsampleType::AVERAGE, 26 | ImageDownsampleType::BICUBIC, 27 | ImageDownsampleType::SUBSAMPLE, 28 | ImageDownsampleType::NONE, 29 | ]; 30 | 31 | $this->assertEquals($values, ImageDownsampleType::values()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /tests/src/Enum/MonoImageFilterTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\MonoImageFilter; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The monochrome image filter enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\MonoImageFilter::class)] 20 | class MonoImageFilterTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | MonoImageFilter::CCITT_FAX_ENCODE, 26 | MonoImageFilter::FLATE_ENCODE, 27 | MonoImageFilter::RUN_LENGTH_ENCODE 28 | ]; 29 | 30 | $this->assertEquals($values, MonoImageFilter::values()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/Enum/PdfSettingsTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\PdfSettings; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The PDF settings enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\PdfSettings::class)] 20 | class PdfSettingsTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | PdfSettings::__DEFAULT, 26 | PdfSettings::SCREEN, 27 | PdfSettings::EBOOK, 28 | PdfSettings::PRINTER, 29 | PdfSettings::PREPRESS 30 | ]; 31 | 32 | $this->assertEquals($values, PdfSettings::values()); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /tests/src/Enum/ProcessColorModelTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\ProcessColorModel; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The binding enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\ProcessColorModel::class)] 20 | class ProcessColorModelTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | ProcessColorModel::DEVICE_RGB, 26 | ProcessColorModel::DEVICE_CMYK, 27 | ProcessColorModel::DEVICE_GRAY 28 | ]; 29 | 30 | $this->assertEquals($values, ProcessColorModel::values()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/Enum/TransferFunctionInfoTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\TransferFunctionInfo; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The transfer function info enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\TransferFunctionInfo::class)] 20 | class TransferFunctionInfoTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | TransferFunctionInfo::PRESERVE, 26 | TransferFunctionInfo::REMOVE, 27 | TransferFunctionInfo::APPLY 28 | ]; 29 | 30 | $this->assertEquals($values, TransferFunctionInfo::values()); 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /tests/src/Enum/UcrAndBgInfoTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Enum; 9 | 10 | use GravityMedia\Ghostscript\Enum\UcrAndBgInfo; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The UCR and BG info enum test class 16 | * 17 | * @package GravityMedia\GhostscriptTest\Enum 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Enum\UcrAndBgInfo::class)] 20 | class UcrAndBgInfoTest extends TestCase 21 | { 22 | public function testValues() 23 | { 24 | $values = [ 25 | UcrAndBgInfo::PRESERVE, 26 | UcrAndBgInfo::REMOVE 27 | ]; 28 | 29 | $this->assertEquals($values, UcrAndBgInfo::values()); 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /tests/src/GhostscriptTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest; 9 | 10 | use GravityMedia\Ghostscript\Device\BoundingBoxInfo; 11 | use GravityMedia\Ghostscript\Device\Inkcov; 12 | use GravityMedia\Ghostscript\Device\NoDisplay; 13 | use GravityMedia\Ghostscript\Device\PdfInfo; 14 | use GravityMedia\Ghostscript\Device\PdfWrite; 15 | use GravityMedia\Ghostscript\Ghostscript; 16 | use GravityMedia\Ghostscript\Process\Arguments; 17 | use PHPUnit\Framework\Attributes\CoversClass; 18 | use PHPUnit\Framework\Attributes\UsesClass; 19 | use PHPUnit\Framework\TestCase; 20 | 21 | /** 22 | * The Ghostscript test class 23 | * 24 | * @package GravityMedia\GhostscriptTest 25 | */ 26 | #[CoversClass(\GravityMedia\Ghostscript\Ghostscript::class)] 27 | #[UsesClass(\GravityMedia\Ghostscript\Input::class)] 28 | #[UsesClass(\GravityMedia\Ghostscript\Enum\PdfSettings::class)] 29 | #[UsesClass(\GravityMedia\Ghostscript\Device\AbstractDevice::class)] 30 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\EpsTrait::class)] 31 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\FontTrait::class)] 32 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\IccColorTrait::class)] 33 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\InteractionTrait::class)] 34 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\OtherTrait::class)] 35 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\OutputSelectionTrait::class)] 36 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\PageTrait::class)] 37 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\RenderingTrait::class)] 38 | #[UsesClass(\GravityMedia\Ghostscript\Device\CommandLineParameters\ResourceTrait::class)] 39 | #[UsesClass(\GravityMedia\Ghostscript\Device\DistillerParametersTrait::class)] 40 | #[UsesClass(\GravityMedia\Ghostscript\Device\BoundingBoxInfo::class)] 41 | #[UsesClass(\GravityMedia\Ghostscript\Device\Inkcov::class)] 42 | #[UsesClass(\GravityMedia\Ghostscript\Device\NoDisplay::class)] 43 | #[UsesClass(\GravityMedia\Ghostscript\Device\PdfInfo::class)] 44 | #[UsesClass(\GravityMedia\Ghostscript\Device\PdfWrite::class)] 45 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 46 | #[UsesClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 47 | class GhostscriptTest extends TestCase 48 | { 49 | public function testCreateGhostscriptObject() 50 | { 51 | $this->assertInstanceOf(Ghostscript::class, new Ghostscript()); 52 | } 53 | 54 | /** 55 | * @dataProvider provideOptions 56 | * 57 | * @param array $options 58 | * @param string $name 59 | * @param mixed $value 60 | */ 61 | public function testGetOption(array $options, $name, $value) 62 | { 63 | $instance = new Ghostscript($options); 64 | 65 | $this->assertSame($value, $instance->getOption($name)); 66 | } 67 | 68 | /** 69 | * @return array 70 | */ 71 | public static function provideOptions() 72 | { 73 | return [ 74 | [[], 'foo', null], 75 | [['foo' => 'bar'], 'foo', 'bar'] 76 | ]; 77 | } 78 | 79 | public function testGetVersion() 80 | { 81 | $instance = new Ghostscript(); 82 | 83 | $this->assertMatchesRegularExpression('/^[0-9]+\.[0-9\.]+$/', $instance->getVersion()); 84 | } 85 | 86 | public function testGetVersionThrowsExceptionOnFailure() 87 | { 88 | $this->expectExceptionMessageMatches('/exec: \/foo\/bar\/baz/'); 89 | $ghostscript = new Ghostscript(['bin' => '/foo/bar/baz']); 90 | $ghostscript->getVersion(); 91 | } 92 | 93 | public function testProcessArgumentsCreation() 94 | { 95 | $method = new \ReflectionMethod(Ghostscript::class, 'createArguments'); 96 | $method->setAccessible(true); 97 | 98 | $this->assertInstanceOf(Arguments::class, $method->invoke(new Ghostscript())); 99 | } 100 | 101 | public function testPdfDeviceCreation() 102 | { 103 | $instance = new Ghostscript(); 104 | 105 | $this->assertInstanceOf(PdfWrite::class, $instance->createPdfDevice()); 106 | } 107 | 108 | public function testNullDeviceCreation() 109 | { 110 | $instance = new Ghostscript(); 111 | 112 | $this->assertInstanceOf(NoDisplay::class, $instance->createNoDisplayDevice()); 113 | } 114 | 115 | public function testPdfInfoDeviceCreation() 116 | { 117 | $instance = new Ghostscript(); 118 | $pdfInfoPath = 'path/to/pdf_info.ps'; 119 | $pdfInfo = $instance->createPdfInfoDevice($pdfInfoPath); 120 | 121 | $this->assertInstanceOf(PdfInfo::class, $pdfInfo); 122 | 123 | $field = new \ReflectionProperty(PdfInfo::class, 'pdfInfoPath'); 124 | $field->setAccessible(true); 125 | $this->assertEquals($pdfInfoPath, $field->getValue($pdfInfo)); 126 | } 127 | 128 | public function testBoundingBoxInfoCreation() 129 | { 130 | $instance = new Ghostscript(); 131 | 132 | $this->assertInstanceOf(BoundingBoxInfo::class, $instance->createBoundingBoxInfoDevice()); 133 | } 134 | 135 | public function testInkcovDeviceCreation() 136 | { 137 | $instance = new Ghostscript(); 138 | $device = $instance->createInkcovDevice(); 139 | 140 | $this->assertInstanceOf(Inkcov::class, $device); 141 | $this->assertEquals("'gs' '-o' '-' '-sDEVICE=inkcov'", $device->createProcess()->getCommandLine()); 142 | } 143 | 144 | /** 145 | * @dataProvider provideTimeout 146 | * 147 | * @param null|int $value 148 | * @param null|int $result 149 | */ 150 | public function testTimeoutOption($value, $result) 151 | { 152 | $instance = new Ghostscript(['timeout' => $value]); 153 | $device = $instance->createPdfDevice('/path/to/output/file.pdf'); 154 | $process = $device->createProcess(__DIR__ . '/../data/input.pdf'); 155 | 156 | $this->assertEquals($result, $process->getTimeout()); 157 | } 158 | 159 | /** 160 | * @return array 161 | */ 162 | public static function provideTimeout() 163 | { 164 | return [ 165 | [42, 42], 166 | [0, null], 167 | [null, null], 168 | ]; 169 | } 170 | } 171 | -------------------------------------------------------------------------------- /tests/src/InputTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest; 9 | 10 | use GravityMedia\Ghostscript\Input; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The input test class 16 | * 17 | * @package GravityMedia\GhostscriptTest 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Input::class)] 20 | class InputTest extends TestCase 21 | { 22 | public function testDefaultInput() 23 | { 24 | $input = new Input(); 25 | 26 | $this->assertNull($input->getProcessInput()); 27 | $this->assertNull($input->getPostScriptCode()); 28 | $this->assertContainsOnly('array', $input->getFiles()); 29 | $this->assertCount(0, $input->getFiles()); 30 | } 31 | 32 | public function testInput() 33 | { 34 | $input = new Input(); 35 | $input->setProcessInput('input'); 36 | $input->setPostScriptCode('.setpdfwrite'); 37 | $input->addFile('/path/to/output/file.pdf'); 38 | $input->setFiles(['/path/to/output/file.pdf']); 39 | 40 | $this->assertSame('input', $input->getProcessInput()); 41 | $this->assertSame('.setpdfwrite', $input->getPostScriptCode()); 42 | $this->assertContainsOnly('string', $input->getFiles()); 43 | $this->assertCount(1, $input->getFiles()); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /tests/src/Process/ArgumentTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Process; 9 | 10 | use GravityMedia\Ghostscript\Process\Argument; 11 | use PHPUnit\Framework\Attributes\CoversClass; 12 | use PHPUnit\Framework\TestCase; 13 | 14 | /** 15 | * The process argument test class. 16 | * 17 | * @package GravityMedia\GhostscriptTest\Process 18 | */ 19 | #[CoversClass(\GravityMedia\Ghostscript\Process\Argument::class)] 20 | class ArgumentTest extends TestCase 21 | { 22 | /** 23 | * @dataProvider provideConstructorArguments 24 | * 25 | * @param string $name 26 | * @param mixed $value 27 | */ 28 | public function testArgumentConstruction($name, $value) 29 | { 30 | $instance = new Argument($name, $value); 31 | 32 | $this->assertSame($name, $instance->getName()); 33 | $this->assertSame($value, $instance->getValue()); 34 | } 35 | 36 | /** 37 | * @return array 38 | */ 39 | public static function provideConstructorArguments() 40 | { 41 | return [ 42 | ['name', null], 43 | ['name', 'value'] 44 | ]; 45 | } 46 | 47 | /** 48 | * @dataProvider provideArgumentStrings 49 | * 50 | * @param string $string 51 | * @param string $name 52 | * @param mixed $value 53 | */ 54 | public function testArgumentConstructionFromString($string, $name, $value) 55 | { 56 | $instance = Argument::fromString($string); 57 | 58 | $this->assertSame($name, $instance->getName()); 59 | $this->assertSame($value, $instance->getValue()); 60 | } 61 | 62 | /** 63 | * @dataProvider provideArgumentStrings 64 | * 65 | * @param string $string 66 | * @param string $name 67 | * @param mixed $value 68 | */ 69 | public function testArgumentStringResult($string, $name, $value) 70 | { 71 | $instance = new Argument($name, $value); 72 | 73 | $this->assertSame($string, $instance->toString()); 74 | } 75 | 76 | /** 77 | * @return array 78 | */ 79 | public static function provideArgumentStrings() 80 | { 81 | return [ 82 | ['name', 'name', null], 83 | ['name=value', 'name', 'value'] 84 | ]; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /tests/src/Process/ArgumentsTest.php: -------------------------------------------------------------------------------- 1 | 6 | */ 7 | 8 | namespace GravityMedia\GhostscriptTest\Process; 9 | 10 | use GravityMedia\Ghostscript\Process\Argument; 11 | use GravityMedia\Ghostscript\Process\Arguments; 12 | use PHPUnit\Framework\Attributes\CoversClass; 13 | use PHPUnit\Framework\Attributes\UsesClass; 14 | use PHPUnit\Framework\TestCase; 15 | 16 | /** 17 | * The arguments test class. 18 | * 19 | * @package GravityMedia\GhostscriptTest\Process 20 | */ 21 | #[CoversClass(\GravityMedia\Ghostscript\Process\Arguments::class)] 22 | #[UsesClass(\GravityMedia\Ghostscript\Process\Argument::class)] 23 | class ArgumentsTest extends TestCase 24 | { 25 | public function testArgumentsConstruction() 26 | { 27 | $instance = new Arguments(); 28 | 29 | $this->assertEquals([], $instance->toArray()); 30 | } 31 | 32 | /** 33 | * @expectedException \InvalidArgumentException 34 | */ 35 | public function testArgumentConversionThrowsExceptionOnInvalidArgument() 36 | { 37 | $this->expectExceptionMessage('Invalid argument'); 38 | 39 | $method = new \ReflectionMethod(Arguments::class, 'convertArgument'); 40 | $method->setAccessible(true); 41 | 42 | $method->invoke(new Arguments(), 0); 43 | } 44 | 45 | /** 46 | * @dataProvider provideArgumentsForAddition 47 | * 48 | * @param array $arguments 49 | * @param array $expected 50 | */ 51 | public function testAddingArguments($arguments, $expected) 52 | { 53 | $instance = new Arguments(); 54 | $instance->addArguments($arguments); 55 | 56 | $this->assertEquals($expected, $instance->toArray()); 57 | } 58 | 59 | /** 60 | * @return array 61 | */ 62 | public static function provideArgumentsForAddition() 63 | { 64 | return [ 65 | [['foo'], ['foo']], 66 | [['foo', 'foo'], ['foo', 'foo']], 67 | [['foo', 'foo=bar'], ['foo', 'foo=bar']] 68 | ]; 69 | } 70 | 71 | /** 72 | * @dataProvider provideArgumentsForSetting 73 | * 74 | * @param array $arguments 75 | * @param array $expected 76 | */ 77 | public function testSettingArguments($arguments, $expected) 78 | { 79 | $instance = new Arguments(); 80 | $instance->setArguments($arguments); 81 | 82 | $this->assertEquals($expected, $instance->toArray()); 83 | } 84 | 85 | /** 86 | * @return array 87 | */ 88 | public static function provideArgumentsForSetting() 89 | { 90 | return [ 91 | [['foo'], ['foo']], 92 | [['foo', 'foo'], ['foo']], 93 | [['foo', 'foo=bar'], ['foo=bar']] 94 | ]; 95 | } 96 | 97 | public function testGetArgument() 98 | { 99 | $instance = new Arguments(); 100 | $instance->setArgument('foo=bar'); 101 | 102 | $this->assertInstanceOf(Argument::class, $instance->getArgument('foo')); 103 | $this->assertSame('bar', $instance->getArgument('foo')->getValue()); 104 | $this->assertNull($instance->getArgument('bar')); 105 | } 106 | } 107 | --------------------------------------------------------------------------------