├── .github └── workflows │ ├── coding-style.yml │ └── main.yml ├── LICENSE ├── README.md ├── composer.json ├── phpstan.neon └── src ├── Configuration.php ├── Convertor.php └── ConvertorException.php /.github/workflows/coding-style.yml: -------------------------------------------------------------------------------- 1 | name: Coding Style 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | nette_cc: 7 | name: Nette Code Checker 8 | runs-on: ubuntu-latest 9 | steps: 10 | - uses: actions/checkout@v2 11 | - uses: shivammathur/setup-php@v2 12 | with: 13 | php-version: 8.1 14 | coverage: none 15 | 16 | - run: composer create-project nette/code-checker temp/code-checker ^3 --no-progress 17 | - run: php temp/code-checker/code-checker --strict-types --no-progress 18 | 19 | nette_cs: 20 | name: Nette Coding Standard 21 | runs-on: ubuntu-latest 22 | steps: 23 | - uses: actions/checkout@v2 24 | - uses: shivammathur/setup-php@v2 25 | with: 26 | php-version: 8.1 27 | coverage: none 28 | 29 | - run: composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress --ignore-platform-reqs 30 | - run: php temp/coding-standard/ecs check src 31 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Integrity check 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | pull_request: 8 | types: [ assigned, opened, synchronize, reopened ] 9 | schedule: 10 | - cron: '1 * * * *' 11 | 12 | jobs: 13 | build: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@master 18 | 19 | - name: Install PHP 20 | uses: shivammathur/setup-php@master 21 | with: 22 | php-version: 8.1 23 | 24 | - name: Install composer deps 25 | run: | 26 | composer create-project nette/code-checker temp/code-checker ^3 --no-progress 27 | composer create-project nette/coding-standard temp/coding-standard ^3 --no-progress 28 | 29 | # Install app deps 30 | composer install --no-interaction --prefer-dist 31 | 32 | - name: The PHP Security Checker 33 | uses: symfonycorp/security-checker-action@v3 34 | 35 | - name: Check PHPStan rules 36 | run: composer phpstan 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Baraja packages 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | PDF to image convertor 2 | ====================== 3 | 4 | Convert PDF to image and save to disk. Convert PDF to JPG, PNG or GIF in PHP. 5 | 6 | 📦 Installation 7 | --------------- 8 | 9 | It's best to use [Composer](https://getcomposer.org) for installation, and you can also find the package on 10 | [Packagist](https://packagist.org/packages/baraja-core/php-pdf-to-image) and 11 | [GitHub](https://github.com/baraja-core/php-pdf-to-image). 12 | 13 | To install, simply use the command: 14 | 15 | ```shell 16 | $ composer require baraja-core/php-pdf-to-image 17 | ``` 18 | 19 | You can use the package manually by creating an instance of the internal classes, or register a DIC extension to link the services directly to the Nette Framework. 20 | 21 | How to use 22 | ---------- 23 | 24 | ```php 25 | $configuration = new Configuration( 26 | pdfPath: __DIR__ . '/example.pdf', 27 | savePath: __DIR__ . '/example.jpg', 28 | format: 'jpg' 29 | ); 30 | 31 | // Render PDF to image and save to disk. 32 | \Baraja\PdfToImage\Convertor::convert($configuration); 33 | ``` 34 | 35 | Supported configuration options 36 | ------------------------------- 37 | 38 | | Name | Type | Default value | 39 | |------------|---------------|---------------| 40 | | `pdfPath` | `string` | | 41 | | `savePath` | `string` | | 42 | | `format` | `string` | `'jpg'` | 43 | | `trim` | `bool` | `false` | 44 | | `cols` | `int`, `null` | `null` | 45 | | `rows` | `int`, `null` | `null` | 46 | | `bestfit` | `bool` | `false` | 47 | 48 | 📄 License 49 | ----------- 50 | 51 | `baraja-core/php-pdf-to-image` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/template/blob/master/LICENSE) file for more details. 52 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "baraja-core/php-pdf-to-image", 3 | "description": "Convert PDF to JPG, PNG or GIF in PHP.", 4 | "homepage": "https://github.com/baraja-core/php-pdf-to-image", 5 | "authors": [ 6 | { 7 | "name": "Jan Barášek", 8 | "homepage": "https://baraja.cz" 9 | } 10 | ], 11 | "require": { 12 | "php": "^8.0", 13 | "ext-imagick": "*" 14 | }, 15 | "require-dev": { 16 | "phpstan/phpstan": "^1.0", 17 | "phpstan/extension-installer": "^1.1", 18 | "phpstan/phpstan-nette": "^1.0", 19 | "phpstan/phpstan-deprecation-rules": "^1.0", 20 | "phpstan/phpstan-strict-rules": "^1.0", 21 | "spaze/phpstan-disallowed-calls": "^2.0", 22 | "roave/security-advisories": "dev-master" 23 | }, 24 | "autoload": { 25 | "classmap": [ 26 | "src/" 27 | ] 28 | }, 29 | "scripts": { 30 | "phpstan": [ 31 | "vendor/bin/phpstan analyse src -c phpstan.neon --level 8 --no-progress" 32 | ] 33 | }, 34 | "minimum-stability": "stable", 35 | "config": { 36 | "allow-plugins": { 37 | "phpstan/extension-installer": true 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /phpstan.neon: -------------------------------------------------------------------------------- 1 | includes: 2 | - vendor/spaze/phpstan-disallowed-calls/disallowed-dangerous-calls.neon 3 | - vendor/spaze/phpstan-disallowed-calls/disallowed-execution-calls.neon 4 | -------------------------------------------------------------------------------- /src/Configuration.php: -------------------------------------------------------------------------------- 1 | format = strtolower($format); 28 | if (in_array($this->format, self::SupportedFormats, true) === false) { 29 | throw new \InvalidArgumentException(sprintf( 30 | 'Format "%s" is not supported. Did you mean "%s"?', 31 | $this->format, 32 | implode('", "', self::SupportedFormats), 33 | )); 34 | } 35 | if (is_file($pdfPath) === false) { 36 | throw new ConvertorException(sprintf('File "%s" does not exist.', $pdfPath)); 37 | } 38 | } 39 | 40 | 41 | public static function from( 42 | string $pdfPath, 43 | string $savePath, 44 | string $format = 'jpg', 45 | bool $trim = false, 46 | ): self { 47 | return new self( 48 | pdfPath: $pdfPath, 49 | savePath: $savePath, 50 | format: $format, 51 | trim: $trim, 52 | ); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/Convertor.php: -------------------------------------------------------------------------------- 1 | getMessage(), $e->getCode(), $e); 28 | } 29 | } 30 | 31 | 32 | /** 33 | * @throws \ImagickException 34 | */ 35 | private static function process(Configuration $configuration): void 36 | { 37 | if (class_exists('\Imagick') === false) { 38 | throw new \RuntimeException('Imagick is not installed.'); 39 | } 40 | 41 | $im = new \Imagick($configuration->pdfPath); 42 | $im->setImageFormat($configuration->format); 43 | if ($configuration->cols !== null && $configuration->rows !== null) { 44 | $im->scaleImage($configuration->cols, $configuration->rows, $configuration->bestfit); 45 | } 46 | if ($configuration->trim) { 47 | $im->setImageBorderColor('rgb(255,255,255)'); 48 | $im->trimImage(1); 49 | } 50 | self::write($configuration->savePath, (string) $im); 51 | } 52 | 53 | 54 | /** 55 | * Writes a string to a file. Moved from nette/utils 56 | * 57 | * @throws ConvertorException 58 | */ 59 | private static function write(string $file, string $content, ?int $mode = 0_666): void 60 | { 61 | self::createDir(dirname($file)); 62 | if (@file_put_contents($file, $content) === false) { // @ is escalated to exception 63 | throw new ConvertorException(sprintf('Unable to write file "%s": %s', $file, self::getLastError())); 64 | } 65 | if ($mode !== null && !@chmod($file, $mode)) { // @ is escalated to exception 66 | throw new ConvertorException(sprintf('Unable to chmod file "%s": %s', $file, self::getLastError())); 67 | } 68 | } 69 | 70 | 71 | /** 72 | * Creates a directory. Moved from nette/utils 73 | * 74 | * @throws ConvertorException 75 | */ 76 | private static function createDir(string $dir, int $mode = 0_777): void 77 | { 78 | if (!is_dir($dir) && !@mkdir($dir, $mode, true) && !is_dir($dir)) { // @ - dir may already exist 79 | throw new ConvertorException(sprintf('Unable to create directory "%s": %s', $dir, self::getLastError())); 80 | } 81 | } 82 | 83 | 84 | private static function getLastError(): string 85 | { 86 | return (string) preg_replace('#^\w+\(.*?\): #', '', error_get_last()['message'] ?? ''); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/ConvertorException.php: -------------------------------------------------------------------------------- 1 |