Replace TCPDI by TCPDF

TCPDI have problems when manipulate the original PDF file. The approach
to add footer at PDF files was replaced by create an overlay to each
page and merge with original PDF file.

Signed-off-by: Vitor Mattos <vitor@php.rio>
This commit is contained in:
Vitor Mattos 2024-03-27 14:28:40 -03:00
parent b496de134a
commit d0932e938c
No known key found for this signature in database
GPG key ID: B7AB4B76A7CA7318
11 changed files with 62 additions and 233 deletions

View file

@ -5,13 +5,12 @@
"license": "AGPL",
"require": {
"endroid/qr-code": "^4.6",
"iio/libmergepdf": "dev-move-tcpdi-parser-to-package",
"jsignpdf/jsignpdf-php": "^1.2",
"mikehaertl/php-pdftk": "^0.13.0",
"pagerfanta/pagerfanta": "^3.6",
"smalot/pdfparser": "^2.4",
"symfony/console": "^5.4",
"tecnickcom/tcpdf": "^6.4",
"tecnickcom/tcpdf": "^6.7",
"wobeto/email-blur": "^1.0"
},
"require-dev": {
@ -62,11 +61,5 @@
"psr-4": {
"OCP\\": "vendor/nextcloud/ocp/OCP"
}
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/LibreCodeCoop/libmergepdf"
}
]
}
}

181
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "e680dc2da1aee7d230b344aa0367ca37",
"content-hash": "3b8c5d2bdc7f7847621f5e16ffc8e7fc",
"packages": [
{
"name": "bacon/bacon-qr-code",
@ -185,65 +185,6 @@
],
"time": "2023-03-30T18:46:02+00:00"
},
{
"name": "iio/libmergepdf",
"version": "dev-move-tcpdi-parser-to-package",
"source": {
"type": "git",
"url": "https://github.com/LibreSign/libmergepdf.git",
"reference": "4304a115056e595725e6105a42e47cebe0416ed2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/LibreSign/libmergepdf/zipball/4304a115056e595725e6105a42e47cebe0416ed2",
"reference": "4304a115056e595725e6105a42e47cebe0416ed2",
"shasum": ""
},
"require": {
"libresign/tcpdi_parser": "^0.4.0",
"php": "^7.1||^8.0",
"setasign/fpdi": "^2",
"tecnickcom/tcpdf": "^6.2.22"
},
"conflict": {
"rafikhaceb/tcpdi": "*",
"setasign/fpdf": "*"
},
"require-dev": {
"behat/behat": "^3.10",
"phpspec/prophecy-phpunit": "^2.0",
"phpunit/phpunit": "^9.5",
"smalot/pdfparser": "~0.13"
},
"type": "library",
"autoload": {
"psr-4": {
"iio\\libmergepdf\\": "src/"
},
"classmap": [
"tcpdi/"
]
},
"license": [
"WTFPL"
],
"authors": [
{
"name": "Hannes Forsgård",
"email": "hannes.forsgard@fripost.org"
}
],
"description": "Library for merging multiple PDFs",
"homepage": "https://github.com/hanneskod/libmergepdf",
"keywords": [
"merge",
"pdf"
],
"support": {
"source": "https://github.com/LibreSign/libmergepdf/tree/move-tcpdi-parser-to-package"
},
"time": "2022-01-30T18:52:29+00:00"
},
{
"name": "jsignpdf/jsignpdf-php",
"version": "v1.2.3",
@ -297,45 +238,6 @@
},
"time": "2022-12-02T17:27:21+00:00"
},
{
"name": "libresign/tcpdi_parser",
"version": "v0.4",
"source": {
"type": "git",
"url": "https://github.com/LibreSign/tcpdi_parser.git",
"reference": "c958caddb089e8986a509dc538cda0c5e14f18a2"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/LibreSign/tcpdi_parser/zipball/c958caddb089e8986a509dc538cda0c5e14f18a2",
"reference": "c958caddb089e8986a509dc538cda0c5e14f18a2",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-4": {
"LibreSign\\TcpdiParser\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"LGPL-3.0-or-later"
],
"authors": [
{
"name": "Vitor Mattos",
"email": "vitor@php.rio"
},
{
"name": "Paul Nicholls",
"homepage": "https://github.com/pauln"
}
],
"support": {
"source": "https://github.com/LibreSign/tcpdi_parser/tree/v0.4"
},
"time": "2022-01-30T18:39:05+00:00"
},
{
"name": "mikehaertl/php-pdftk",
"version": "0.13.1",
@ -631,78 +533,6 @@
},
"time": "2021-11-05T16:47:00+00:00"
},
{
"name": "setasign/fpdi",
"version": "v2.6.0",
"source": {
"type": "git",
"url": "https://github.com/Setasign/FPDI.git",
"reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Setasign/FPDI/zipball/a6db878129ec6c7e141316ee71872923e7f1b7ad",
"reference": "a6db878129ec6c7e141316ee71872923e7f1b7ad",
"shasum": ""
},
"require": {
"ext-zlib": "*",
"php": "^5.6 || ^7.0 || ^8.0"
},
"conflict": {
"setasign/tfpdf": "<1.31"
},
"require-dev": {
"phpunit/phpunit": "~5.7",
"setasign/fpdf": "~1.8.6",
"setasign/tfpdf": "~1.33",
"squizlabs/php_codesniffer": "^3.5",
"tecnickcom/tcpdf": "~6.2"
},
"suggest": {
"setasign/fpdf": "FPDI will extend this class but as it is also possible to use TCPDF or tFPDF as an alternative. There's no fixed dependency configured."
},
"type": "library",
"autoload": {
"psr-4": {
"setasign\\Fpdi\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jan Slabon",
"email": "jan.slabon@setasign.com",
"homepage": "https://www.setasign.com"
},
{
"name": "Maximilian Kresse",
"email": "maximilian.kresse@setasign.com",
"homepage": "https://www.setasign.com"
}
],
"description": "FPDI is a collection of PHP classes facilitating developers to read pages from existing PDF documents and use them as templates in FPDF. Because it is also possible to use FPDI with TCPDF, there are no fixed dependencies defined. Please see suggestions for packages which evaluates the dependencies automatically.",
"homepage": "https://www.setasign.com/fpdi",
"keywords": [
"fpdf",
"fpdi",
"pdf"
],
"support": {
"issues": "https://github.com/Setasign/FPDI/issues",
"source": "https://github.com/Setasign/FPDI/tree/v2.6.0"
},
"funding": [
{
"url": "https://tidelift.com/funding/github/packagist/setasign/fpdi",
"type": "tidelift"
}
],
"time": "2023-12-11T16:03:32+00:00"
},
{
"name": "smalot/pdfparser",
"version": "v2.9.0",
@ -1567,12 +1397,12 @@
"source": {
"type": "git",
"url": "https://github.com/tecnickcom/TCPDF.git",
"reference": "f9fd21807cbb5d43ed62c685e2d6467515d31746"
"reference": "d4adef47ca21c90e6483d59dcb9e5b1023696937"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/f9fd21807cbb5d43ed62c685e2d6467515d31746",
"reference": "f9fd21807cbb5d43ed62c685e2d6467515d31746",
"url": "https://api.github.com/repos/tecnickcom/TCPDF/zipball/d4adef47ca21c90e6483d59dcb9e5b1023696937",
"reference": "d4adef47ca21c90e6483d59dcb9e5b1023696937",
"shasum": ""
},
"require": {
@ -1631,7 +1461,7 @@
"type": "custom"
}
],
"time": "2024-03-21T09:36:59+00:00"
"time": "2024-03-25T23:56:24+00:00"
},
{
"name": "wobeto/email-blur",
@ -2669,7 +2499,6 @@
"aliases": [],
"minimum-stability": "stable",
"stability-flags": {
"iio/libmergepdf": 20,
"nextcloud/ocp": 20,
"roave/security-advisories": 20
},

View file

@ -25,6 +25,7 @@ declare(strict_types=1);
namespace OCA\Libresign\Db;
use OCP\AppFramework\Db\Entity;
use stdClass;
/**
* @method void setId(int $id)
@ -45,8 +46,7 @@ use OCP\AppFramework\Db\Entity;
* @method string getCallback()
* @method void setStatus(int $status)
* @method int getStatus()
* @method void setPages(int $pages)
* @method int getPages()
* @method string getMetadata()
*/
class File extends Entity {
/** @var integer */
@ -97,4 +97,16 @@ class File extends Entity {
$this->addType('status', 'integer');
$this->addType('metadata', 'string');
}
public function setMetadata($metadata): void {
if (is_array($metadata)) {
$metadata = json_encode($metadata);
}
$this->metadata = (string) $metadata;
$this->markFieldUpdated('metadata');
}
public function getMetadataDecoded(): ?stdClass {
return json_decode($this->metadata);
}
}

View file

@ -43,7 +43,7 @@ use OCP\DB\Types;
* @method void setDisplayName(string $displayName)
* @method string getDisplayName()
* @method void setMetadata(array $metadata)
* @method string getMetadata()
* @method array getMetadata()
*/
class SignRequest extends Entity {
/** @var integer */

View file

@ -69,9 +69,6 @@ class SignRequestMapper extends QBMapper {
try {
$fromDatabase = $this->getById($signRequest->getId());
$metadata = $fromDatabase->getMetadata();
if (!empty($metadata)) {
$metadata = json_decode($metadata, true);
}
if (!isset($metadata['notify'])) {
$this->firstNotification = true;
}

View file

@ -33,14 +33,16 @@ use Endroid\QrCode\Matrix\Matrix;
use Endroid\QrCode\QrCode;
use Endroid\QrCode\RoundBlockSizeMode\RoundBlockSizeModeMargin;
use OC\SystemConfig;
use OCA\Libresign\Db\File as FileEntity;
use OCA\Libresign\Exception\LibresignException;
use OCA\Libresign\Handler\CertificateEngine\Handler as CertificateEngineHandler;
use OCA\Libresign\Service\FolderService;
use OCA\Libresign\Service\PdfParserService;
use OCP\AppFramework\Services\IAppConfig;
use OCP\Files\File;
use OCP\IL10N;
use OCP\IURLGenerator;
use TCPDI;
use TCPDF;
use TypeError;
class Pkcs12Handler extends SignEngineHandler {
@ -59,6 +61,7 @@ class Pkcs12Handler extends SignEngineHandler {
private CertificateEngineHandler $certificateEngineHandler,
private IL10N $l10n,
private JSignPdfHandler $jSignPdfHandler,
private PdfParserService $pdfParserService,
) {
}
@ -159,42 +162,33 @@ class Pkcs12Handler extends SignEngineHandler {
/**
* @psalm-suppress MixedReturnStatement
*/
public function getFooter(File $file, string $uuid): string {
public function getFooter(File $file, FileEntity $fileEntity): string {
$add_footer = (bool) $this->appConfig->getAppValue('add_footer', '1');
if (!$add_footer) {
return '';
}
$metadata = $fileEntity->getMetadata();
if (!is_array($metadata) || !isset($metadata['d'])) {
$metadata = $this->pdfParserService->getMetadata($file);
}
$validation_site = $this->appConfig->getAppValue('validation_site');
if ($validation_site) {
$validation_site = rtrim($validation_site, '/').'/'.$uuid;
$validation_site = rtrim($validation_site, '/').'/'.$fileEntity->getUuid();
} else {
$validation_site = $this->urlGenerator->linkToRouteAbsolute('libresign.page.validationFileWithShortUrl', ['uuid' => $uuid]);
$validation_site = $this->urlGenerator->linkToRouteAbsolute('libresign.page.validationFileWithShortUrl', ['uuid' => $fileEntity->getUuid()]);
}
$pdf = new TCPDILibresign();
$pageCount = $pdf->setSourceData($file->getContent());
$dimensions = null;
for ($pageNo = 1; $pageNo <= $pageCount; $pageNo++) {
$pdf->importPage($pageNo);
// Define dimensions of page
$tpl = $pdf->tpls[$pageNo];
$dimensions['or'] = $tpl['w'] > $tpl['h'] ? 'L' : 'P';
$pdf->setPageOrientation($dimensions['or']);
$dimensions = $pdf->getPageDimensions($pageNo - 1);
$dimensions['w'] = $tpl['w'];
$dimensions['h'] = $tpl['h'];
$dimensions['wk'] = $tpl['h'];
$dimensions['hk'] = $tpl['h'];
foreach (['MediaBox', 'CropBox', 'BleedBox', 'TrimBox', 'ArtBox'] as $box) {
if (!isset($dimensions[$box])) {
continue;
}
$dimensions[$box]['urx'] = $tpl['h'];
$dimensions[$box]['ury'] = $tpl['w'];
}
$pdf->AddPage($dimensions['or'], $dimensions);
$pdf = new TCPDFLibresign();
foreach ($metadata['d'] as $dimension) {
$orientation = $dimension['w'] > $dimension['h'] ? 'L' : 'P';
$pdf->AddPage($orientation, [
'MediaBox' => [
'llx' => 0,
'lly' => 0,
'urx' => $dimension['w'],
'ury' => $dimension['h'],
]
]);
$pdf->SetFont('Helvetica');
$pdf->SetFontSize(8);
@ -232,7 +226,7 @@ class Pkcs12Handler extends SignEngineHandler {
return $pdf->Output('', 'S');
}
private function writeQrCode(string $text, TCPDI $fpdf): void {
private function writeQrCode(string $text, TCPDF $fpdf): void {
$this->qrCode = QrCode::create($text)
->setEncoding(new Encoding('UTF-8'))
->setErrorCorrectionLevel(new ErrorCorrectionLevelLow())

View file

@ -24,9 +24,9 @@ declare(strict_types=1);
namespace OCA\Libresign\Handler;
use TCPDI;
use TCPDF;
class TCPDILibresign extends TCPDI {
class TCPDFLibresign extends TCPDF {
/**
* @var bool
*/

View file

@ -34,7 +34,7 @@ class FileElementService {
public function __construct(
private FileMapper $fileMapper,
private FileElementMapper $fileElementMapper,
private ITimeFactory $timeFactory
private ITimeFactory $timeFactory,
) {
}
@ -77,13 +77,13 @@ class FileElementService {
private function translateCoordinatesToInternalNotation(array $properties, File $file): array {
$translated['page'] = $properties['coordinates']['page'] ?? 1;
$metadata = json_decode($file->getMetadata(), true);
$dimension = $metadata['d'][$translated['page'] - 1];
$metadata = $file->getMetadataDecoded();
$dimension = $metadata->d[$translated['page'] - 1];
if (isset($properties['coordinates']['ury'])) {
$translated['ury'] = $properties['coordinates']['ury'];
} elseif (isset($properties['coordinates']['top'])) {
$translated['ury'] = $dimension['h'] - $properties['coordinates']['top'];
$translated['ury'] = $dimension->h - $properties['coordinates']['top'];
} else {
$translated['ury'] = 0;
}
@ -131,12 +131,12 @@ class FileElementService {
}
public function translateCoordinatesFromInternalNotation(array $properties, File $file): array {
$metadata = json_decode($file->getMetadata(), true);
$dimension = $metadata['d'][$properties['coordinates']['page'] - 1];
$metadata = $file->getMetadataDecoded();
$dimension = $metadata->d[$properties['coordinates']['page'] - 1];
$translated['left'] = $properties['coordinates']['llx'];
$translated['height'] = abs($properties['coordinates']['ury'] - $properties['coordinates']['lly']);
$translated['top'] = $dimension['h'] - $properties['coordinates']['ury'];
$translated['top'] = $dimension->h - $properties['coordinates']['ury'];
$translated['width'] = $properties['coordinates']['urx'] - $properties['coordinates']['llx'];
return $translated;

View file

@ -259,7 +259,7 @@ class FileService {
private function getPages(): array {
$return = [];
$metadata = json_decode($this->file->getMetadata());
$metadata = $this->file->getMetadataDecoded();
for ($page = 1; $page <= $metadata->p; $page++) {
$return[] = [
'url' => $this->urlGenerator->linkToRoute('ocs.libresign.File.getPage', [

View file

@ -535,7 +535,7 @@ class SignFileService {
$originalFile->getPath()
);
$footer = $this->pkcs12Handler->getFooter($originalFile, $fileData->getUuid());
$footer = $this->pkcs12Handler->getFooter($originalFile, $fileData);
if ($footer) {
$background = $this->tempManager->getTemporaryFile('signed.pdf');
file_put_contents($background, $footer);

View file

@ -3,10 +3,10 @@
use OC\SystemConfig;
use OCA\Libresign\Handler\CertificateEngine\CfsslHandler;
use OCA\Libresign\Handler\CertificateEngine\Handler as CertificateEngineHandler;
use OCA\Libresign\Handler\CertificateEngine\OpenSslHandler;
use OCA\Libresign\Handler\JSignPdfHandler;
use OCA\Libresign\Handler\Pkcs12Handler;
use OCA\Libresign\Service\FolderService;
use OCA\Libresign\Service\PdfParserService;
use OCP\AppFramework\Services\IAppConfig;
use OCP\IL10N;
use OCP\IURLGenerator;
@ -21,7 +21,7 @@ final class Pkcs12HandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
private CfsslHandler|MockObject $cfsslHandler;
private IL10N|MockObject $l10n;
private JSignPdfHandler|MockObject $jSignPdfHandler;
private OpenSslHandler|MockObject $openSslHandler;
private PdfParserService|MockObject $pdfParserService;
private CertificateEngineHandler|MockObject $certificateEngineHandler;
private array $cfsslHandlerBuffer = [];
@ -36,6 +36,7 @@ final class Pkcs12HandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
->method('t')
->will($this->returnArgument(0));
$this->jSignPdfHandler = $this->createMock(JSignPdfHandler::class);
$this->pdfParserService = $this->createMock(PdfParserService::class);
$this->pkcs12Handler = new Pkcs12Handler(
$this->folderService,
$this->appConfig,
@ -44,6 +45,7 @@ final class Pkcs12HandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
$this->certificateEngineHandler,
$this->l10n,
$this->jSignPdfHandler,
$this->pdfParserService,
);
}
@ -102,6 +104,7 @@ final class Pkcs12HandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
$this->certificateEngineHandler,
$this->l10n,
$this->jSignPdfHandler,
$this->pdfParserService,
);
$file = $this->createMock(\OCP\Files\File::class);
$actual = $this->pkcs12Handler->getFooter($file, 'uuid');
@ -130,6 +133,7 @@ final class Pkcs12HandlerTest extends \OCA\Libresign\Tests\Unit\TestCase {
$this->certificateEngineHandler,
$this->l10n,
$this->jSignPdfHandler,
$this->pdfParserService,
);
$file = $this->createMock(\OCP\Files\File::class);