Skip to content

Commit

Permalink
feat(Document): Added DocumentPdfMessageHandler to generate thumbnail…
Browse files Browse the repository at this point in the history
… for PDF documents.
  • Loading branch information
ambroisemaupate committed May 5, 2023
1 parent 6c78448 commit 35241bc
Show file tree
Hide file tree
Showing 5 changed files with 126 additions and 1 deletion.
1 change: 0 additions & 1 deletion lib/Documents/src/Renderer/InlineSvgRenderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
use RZ\Roadiz\Documents\Models\DocumentInterface;
use RZ\Roadiz\Documents\OptionsResolver\ViewOptionsResolver;
use RZ\Roadiz\Documents\Viewers\SvgDocumentViewer;
use Symfony\Component\HttpFoundation\File\Exception\FileNotFoundException;

class InlineSvgRenderer implements RendererInterface
{
Expand Down
7 changes: 7 additions & 0 deletions lib/RoadizCoreBundle/config/services.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -291,6 +291,13 @@ services:
handles: RZ\Roadiz\CoreBundle\Document\Message\DocumentAudioVideoMessage
- { name: monolog.logger, channel: messenger }

RZ\Roadiz\CoreBundle\Document\MessageHandler\DocumentPdfMessageHandler:
autoconfigure: false
tags:
- name: messenger.message_handler
handles: RZ\Roadiz\CoreBundle\Document\Message\DocumentPdfMessage
- { name: monolog.logger, channel: messenger }

RZ\Roadiz\CoreBundle\SearchEngine\Indexer\:
resource: '../src/SearchEngine/Indexer/'
# Recreate handlers for each usage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
use RZ\Roadiz\CoreBundle\Document\Message\DocumentAverageColorMessage;
use RZ\Roadiz\CoreBundle\Document\Message\DocumentExifMessage;
use RZ\Roadiz\CoreBundle\Document\Message\DocumentFilesizeMessage;
use RZ\Roadiz\CoreBundle\Document\Message\DocumentPdfMessage;
use RZ\Roadiz\CoreBundle\Document\Message\DocumentRawMessage;
use RZ\Roadiz\CoreBundle\Document\Message\DocumentSizeMessage;
use RZ\Roadiz\CoreBundle\Document\Message\DocumentSvgMessage;
Expand Down Expand Up @@ -59,6 +60,7 @@ public function onFilterDocumentEvent(FilterDocumentEvent $event): void
$this->bus->dispatch(new Envelope(new DocumentExifMessage($document->getId())));
$this->bus->dispatch(new Envelope(new DocumentSvgMessage($document->getId())));
$this->bus->dispatch(new Envelope(new DocumentAudioVideoMessage($document->getId())));
$this->bus->dispatch(new Envelope(new DocumentPdfMessage($document->getId())));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Document\Message;

class DocumentPdfMessage extends AbstractDocumentMessage
{
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<?php

declare(strict_types=1);

namespace RZ\Roadiz\CoreBundle\Document\MessageHandler;

use Doctrine\Persistence\ManagerRegistry;
use League\Flysystem\FilesystemOperator;
use Psr\Log\LoggerInterface;
use RZ\Roadiz\CoreBundle\Document\DocumentFactory;
use RZ\Roadiz\CoreBundle\Document\Message\AbstractDocumentMessage;
use RZ\Roadiz\Documents\Events\DocumentCreatedEvent;
use RZ\Roadiz\Documents\Models\DocumentInterface;
use RZ\Roadiz\Documents\Models\HasThumbnailInterface;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\Messenger\Exception\UnrecoverableMessageHandlingException;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

final class DocumentPdfMessageHandler extends AbstractLockingDocumentMessageHandler
{
private DocumentFactory $documentFactory;
private EventDispatcherInterface $eventDispatcher;

public function __construct(
DocumentFactory $documentFactory,
EventDispatcherInterface $eventDispatcher,
ManagerRegistry $managerRegistry,
LoggerInterface $messengerLogger,
FilesystemOperator $documentsStorage
) {
parent::__construct($managerRegistry, $messengerLogger, $documentsStorage);
$this->documentFactory = $documentFactory;
$this->eventDispatcher = $eventDispatcher;
}

/**
* @param DocumentInterface $document
* @return bool
*/
protected function supports(DocumentInterface $document): bool
{
return $document->isLocal() &&
$document->isPdf() &&
\class_exists('\Imagick') &&
\class_exists('\ImagickException');
}

protected function processMessage(AbstractDocumentMessage $message, DocumentInterface $document): void
{
/*
* This process requires document files to be locally stored!
*/
$pdfPath = \tempnam(\sys_get_temp_dir(), 'pdf_');
\rename($pdfPath, $pdfPath .= $document->getFilename());

/*
* Copy AV locally
*/
$pdfPathResource = \fopen($pdfPath, 'w');
\stream_copy_to_stream($this->documentsStorage->readStream($document->getMountPath()), $pdfPathResource);
\fclose($pdfPathResource);

$this->extractPdfThumbnail($document, $pdfPath);

/*
* Then delete local AV file
*/
\unlink($pdfPath);
}

protected function extractPdfThumbnail(DocumentInterface $document, string $localPdfPath): void
{
if (!$document->isPdf() || !\class_exists('\Imagick') || !\class_exists('\ImagickException')) {
return;
}

$thumbnailPath = \tempnam(\sys_get_temp_dir(), 'thumbnail_');
\rename($thumbnailPath, $thumbnailPath .= $document->getFilename() . '.jpg');

try {
$im = new \Imagick();
$im->setResolution(144, 144);
// Use [0] to get first page of PDF.
if ($im->readImage($localPdfPath . '[0]')) {
$im->writeImages($thumbnailPath, false);

$thumbnailDocument = $this->documentFactory
->setFolder($document->getFolders()->first() ?: null)
->setFile(new File($thumbnailPath))
->getDocument();
if ($thumbnailDocument instanceof HasThumbnailInterface && $document instanceof HasThumbnailInterface) {
$thumbnailDocument->setOriginal($document);
$document->getThumbnails()->add($thumbnailDocument);
$this->managerRegistry->getManager()->flush();
$this->eventDispatcher->dispatch(new DocumentCreatedEvent($thumbnailDocument));
}
}
} catch (\ImagickException $exception) {
throw new UnrecoverableMessageHandlingException(
sprintf(
'Cannot extract thumbnail from %s PDF file : %s',
$localPdfPath,
$exception->getMessage()
),
);
}
}
}

0 comments on commit 35241bc

Please sign in to comment.