Skip to content

Commit

Permalink
Added Gotenberg support for creating page and version previews (pimco…
Browse files Browse the repository at this point in the history
…re#16608)

* Added Gotenberg support for creating page and version previews

* Update lib/Image/HtmlToImage.php

Co-authored-by: JiaJia Ji <[email protected]>

* Update lib/Image/HtmlToImage.php

Co-authored-by: JiaJia Ji <[email protected]>

* Making Stan happy

* added upgrade notes

* docs

* Update composer.json

Co-authored-by: JiaJia Ji <[email protected]>

* deprected Chromium support

* Update lib/Image/HtmlToImage.php

Co-authored-by: JiaJia Ji <[email protected]>

* Added compatibility layer and deprecation notice

* make PhpStan happy

---------

Co-authored-by: JiaJia Ji <[email protected]>
  • Loading branch information
brusch and kingjia90 authored Mar 12, 2024
1 parent 3b9af52 commit 0f909c6
Show file tree
Hide file tree
Showing 11 changed files with 325 additions and 148 deletions.
4 changes: 4 additions & 0 deletions bundles/CoreBundle/src/DependencyInjection/Configuration.php
Original file line number Diff line number Diff line change
Expand Up @@ -1971,11 +1971,15 @@ private function addGotenbergNode(ArrayNodeDefinition $rootNode): void
->end();
}

/**
* @deprecated
*/
private function addChromiumNode(ArrayNodeDefinition $rootNode): void
{
$rootNode
->children()
->arrayNode('chromium')
->setDeprecated('pimcore/pimcore', '11.2', 'Chromium service is deprecated and will be removed in Pimcore 12. Use Gotenberg instead.')
->addDefaultsIfNotSet()
->children()
->scalarNode('uri')
Expand Down
6 changes: 3 additions & 3 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,7 @@
"phpstan/phpstan": "1.10.59",
"phpstan/phpstan-symfony": "^1.3.5",
"phpunit/phpunit": "^9.3",
"gotenberg/gotenberg-php": "^1.1",
"gotenberg/gotenberg-php": "^1.1 || ^2.0",
"composer/composer": "*",
"chrome-php/chrome": "^1.4.0",
"webmozarts/console-parallelization": "^2.1",
Expand All @@ -152,9 +152,9 @@
"ext-sockets": "*",
"ext-imagick": "^3.4.0",
"ext-redis": "*",
"gotenberg/gotenberg-php": "^1.1 - Required for generating pdf via Gotenberg in assets preview (LibreOffice), page preview, version diff and web2print",
"gotenberg/gotenberg-php": "^2.0 - Required for generating pdf via Gotenberg in assets preview (LibreOffice), page preview, version diff and web2print",
"elasticsearch/elasticsearch": "Required for Elastic Search service",
"chrome-php/chrome": "Required for Documents Page Previews",
"chrome-php/chrome": "Optional for Documents Page Previews when requiring gotenberg-php v2, but required if you opt for gotenberg-php v1",
"webmozarts/console-parallelization": "Required for parallelization of console commands",
"symfony/dotenv": "Required for loading environment vars from .env files",
"pimcore/admin-ui-classic-bundle": "^1.4.0"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,26 @@ It's possible to either choose to install LibreOffice/Chromium or to use them vi
apt-get install libreoffice libreoffice-script-provider-python libreoffice-math xfonts-75dpi poppler-utils inkscape libxrender1 libfontconfig1 ghostscript
```

### Chromium (Chrome Headless)
### Gotenberg

To install it, please add it in your Docker Compose services stack as [https://gotenberg.dev/docs/getting-started/installation#docker-compose](https://gotenberg.dev/docs/getting-started/installation#docker-compose).

Configure the Docker services accordingly:

- `pimcore.gotenberg.base_url` which by default to `http://gotenberg:3000`
- `pimcore.documents.preview_url_prefix` for example to `nginx:80`

Make sure to add and install the required library via composer:
```bash
composer require gotenberg/gotenberg-php ^2.0
```


### Chromium (Chrome Headless) - deprecated

> Chromium is used to generate previews of document pages.
> This functionality is now also provided by Gotenberg, therefore Chromium support has been deprecated in favour of Gotenberg.
First of all, you need to add and install the required library via composer:
```bash
composer require chrome-php/chrome
Expand All @@ -51,23 +69,9 @@ Add a new service as:
image: browserless/chrome
```
and set accordingly:
- config `pimcore.chromium.uri` value (e.g. `ws://chrome:3000/`)
- config `pimcore.chromium.uri` value (e.g. `ws://chrome:3000/`)
- web2print settings hostUrl as the Docker web server service (e.g. `http://nginx:80`)

### Gotenberg

To install it, please add it in your Docker Compose services stack as [https://gotenberg.dev/docs/getting-started/installation#docker-compose](https://gotenberg.dev/docs/getting-started/installation#docker-compose).

Configure the Docker services accordingly:

- `pimcore.gotenberg.base_url` which by default to `http://gotenberg:3000`
- `pimcore.documents.preview_url_prefix` for example to `nginx:80`

Make sure to add and install the required library via composer:
```bash
composer require gotenberg/gotenberg-php ^1.1
```

## Image Optimizers

### JPEGOptim
Expand Down
2 changes: 2 additions & 0 deletions doc/23_Installation_and_Upgrade/09_Upgrade_Notes/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
#### [Documents]:
- Using `outputFormat` config for `Pimcore\Model\Document\Editable\Date` editable is deprecated, use `outputIsoFormat` config instead.
- Service `Pimcore\Document\Renderer\DocumentRenderer` is deprecated, use `Pimcore\Document\Renderer\DocumentRendererInterface` instead.
- Page previews and version comparisons can now be rendered using Gotenberg v8.
To replace Headless Chrome, upgrade to Gotenberg v8 and upgrade the client library: `composer require gotenberg/gotenberg-php:^2`
#### [Data Objects]:
- Methods `getAsIntegerCast()` and `getAsFloatCast()` of the `Pimcore\Model\DataObject\Data` class are deprecated now.
- `MultiSelectOptionsProviderInterface` is deprecated, please use `SelectOptionsProviderInterface` instead.
Expand Down
25 changes: 3 additions & 22 deletions lib/Document/Adapter/Gotenberg.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@

namespace Pimcore\Document\Adapter;

use Gotenberg\Exceptions\GotenbergApiErroed;
use Gotenberg\Gotenberg as GotenbergAPI;
use Gotenberg\Stream;
use Pimcore\Config;
use Pimcore\Helper\GotenbergHelper;
use Pimcore\Logger;
use Pimcore\Model\Asset;
use Pimcore\Tool\Storage;
Expand All @@ -29,8 +29,6 @@
*/
class Gotenberg extends Ghostscript
{
protected static bool $validPing = false;

public function isAvailable(): bool
{
try {
Expand Down Expand Up @@ -61,24 +59,7 @@ public function isFileTypeSupported(string $fileType): bool
*/
public static function checkGotenberg(): bool
{
if (self::$validPing) {
return true;
}

if (!class_exists(GotenbergAPI::class, true)) {
return false;
}
$request = GotenbergAPI::chromium(Config::getSystemConfiguration('gotenberg')['base_url'])
->html(Stream::string('dummy.html', '<body></body>'));

try {
GotenbergAPI::send($request);
self::$validPing = true;

return true;
} catch (GotenbergApiErroed $e) {
return false;
}
return GotenbergHelper::isAvailable();
}

public function load(Asset\Document $asset): static
Expand Down Expand Up @@ -151,7 +132,7 @@ public function getPdf(?Asset\Document $asset = null)
rewind($stream);

return $stream;
} catch (GotenbergApiErroed $e) {
} catch (\Exception $e) {
$message = "Couldn't convert document to PDF: " . $asset->getRealFullPath() . ' with Gotenberg: ';
Logger::error($message. $e->getMessage());

Expand Down
57 changes: 57 additions & 0 deletions lib/Helper/GotenbergHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php
declare(strict_types=1);

namespace Pimcore\Helper;

use Gotenberg\Gotenberg as GotenbergAPI;
use Gotenberg\Stream;
use Pimcore\Config;
use function class_exists;
use function method_exists;

/**
* @internal
*/
class GotenbergHelper
{
private static bool $validPing = false;

/**
*
* @throws \Exception
*/
public static function isAvailable(): bool
{
if (self::$validPing) {
return true;
}

if (!class_exists(GotenbergAPI::class, true)) {
return false;
}

$request = null;

/** @var GotenbergAPI|object $chrome */
$chrome = GotenbergAPI::chromium(Config::getSystemConfiguration('gotenberg')['base_url']);
if(method_exists($chrome, 'html')) {
// gotenberg/gotenberg-php API Client v1
$request = $chrome->html(Stream::string('dummy.html', '<body></body>'));
} elseif(method_exists($chrome, 'screenshot')) {
$request = $chrome->screenshot()->html(Stream::string('dummy.html', '<body></body>'));
}

if($request) {
try {
GotenbergAPI::send($request);
self::$validPing = true;

return true;
} catch (\Exception $e) {
// nothing to do
}
}

return false;
}
}
104 changes: 10 additions & 94 deletions lib/Image/Chromium.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,105 +16,21 @@

namespace Pimcore\Image;

use HeadlessChromium\BrowserFactory;
use HeadlessChromium\Communication\Connection;
use HeadlessChromium\Communication\Message;
use Pimcore\Logger;
use Pimcore\Tool\Console;
use function class_alias;
use function class_exists;
use function trigger_deprecation;

/**
* @internal
*/
class Chromium
{
public static function isSupported(): bool
{
if (!class_exists(BrowserFactory::class)) {
return false;
}

$chromiumUri = \Pimcore\Config::getSystemConfiguration('chromium')['uri'];
if (!empty($chromiumUri)) {
try {
return (new Connection($chromiumUri))->connect();
} catch (\Exception $e) {
Logger::debug((string) $e);

return false;
}
}
trigger_deprecation('pimcore/pimcore', '11.2', 'The "%s" class is deprecated, use "%s" instead.', Chromium::class, HtmlToImage::class);

return (bool) self::getChromiumBinary();
}

public static function getChromiumBinary(): ?string
{
foreach (['chromium', 'chrome'] as $app) {
$chromium = Console::getExecutable($app);
if ($chromium) {
return $chromium;
}
}

return null;
}
if (!class_exists(Chromium::class, false)) {
class_alias(HtmlToImage::class, Chromium::class);
}

if (false) {
/**
* @throws \Exception
* @deprecated since Pimcore 11.2, use HtmlToImage instead
*/
public static function convert(string $url, string $outputFile, ?string $sessionName = null, ?string $sessionId = null, string $windowSize = '1280,1024'): bool
class Chromium extends HtmlToImage
{
$chromiumUri = \Pimcore\Config::getSystemConfiguration('chromium')['uri'];
if (!empty($chromiumUri)) {
try {
$browser = BrowserFactory::connectToBrowser($chromiumUri);
} catch (\Exception $e) {
Logger::debug((string) $e);

return false;
}
} else {
$binary = self::getChromiumBinary();
if (!$binary) {
return false;
}
$browserFactory = new BrowserFactory($binary);
$browser = $browserFactory->createBrowser([
'noSandbox' => file_exists('/.dockerenv'),
'startupTimeout' => 120,
'windowSize' => explode(',', $windowSize),
]);
}

try {
$headers = [];
if (null !== $sessionId && null !== $sessionName) {
$headers['Cookie'] = $sessionName . '=' . $sessionId;
}

$page = $browser->createPage();

if (!empty($headers)) {
$page->getSession()->sendMessageSync(new Message(
'Network.setExtraHTTPHeaders',
['headers' => $headers]
));
}

$page->navigate($url)->waitForNavigation();

$page->screenshot([
'captureBeyondViewport' => true,
'clip' => $page->getFullPageClip(),
])->saveToFile($outputFile);
} catch (\Throwable $e) {
Logger::debug('Could not create image from url ' . $url . ': ' . $e);

return false;
} finally {
$browser->close();
}

return true;
}
}
Loading

0 comments on commit 0f909c6

Please sign in to comment.