feat : automatic PDF compression on upload
- Add PdfCompressorService for lossless compression with qpdf - Add DocumentPdfCompressorListener for automatic compression on persist/update - Add app:compress-pdf command for batch compression of existing PDFs Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
73
src/Service/PdfCompressorService.php
Normal file
73
src/Service/PdfCompressorService.php
Normal file
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
class PdfCompressorService
|
||||
{
|
||||
public function compressBase64Pdf(string $base64Data): ?array
|
||||
{
|
||||
// Check if qpdf is available
|
||||
exec('which qpdf', $qpdfPath, $returnCode);
|
||||
if (0 !== $returnCode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Remove data URI prefix if present
|
||||
$originalBase64 = $base64Data;
|
||||
if (str_contains($base64Data, ',')) {
|
||||
$base64Data = explode(',', $base64Data, 2)[1];
|
||||
}
|
||||
|
||||
$pdfContent = base64_decode($base64Data, true);
|
||||
if (false === $pdfContent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$originalSize = strlen($pdfContent);
|
||||
|
||||
// Create temp files
|
||||
$tempInput = tempnam(sys_get_temp_dir(), 'pdf_in_');
|
||||
$tempOutput = tempnam(sys_get_temp_dir(), 'pdf_out_');
|
||||
|
||||
file_put_contents($tempInput, $pdfContent);
|
||||
|
||||
// Compress with qpdf (lossless)
|
||||
$command = sprintf(
|
||||
'qpdf --linearize --object-streams=generate %s %s 2>&1',
|
||||
escapeshellarg($tempInput),
|
||||
escapeshellarg($tempOutput)
|
||||
);
|
||||
|
||||
exec($command, $cmdOutput, $returnCode);
|
||||
|
||||
if (0 !== $returnCode || !file_exists($tempOutput)) {
|
||||
@unlink($tempInput);
|
||||
@unlink($tempOutput);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
$compressedContent = file_get_contents($tempOutput);
|
||||
$compressedSize = strlen($compressedContent);
|
||||
|
||||
@unlink($tempInput);
|
||||
@unlink($tempOutput);
|
||||
|
||||
// Only return compressed version if it's smaller
|
||||
if ($compressedSize >= $originalSize) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Rebuild with data URI prefix
|
||||
$newBase64 = 'data:application/pdf;base64,'.base64_encode($compressedContent);
|
||||
|
||||
return [
|
||||
'path' => $newBase64,
|
||||
'size' => $compressedSize,
|
||||
'originalSize' => $originalSize,
|
||||
'saved' => $originalSize - $compressedSize,
|
||||
];
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user