php - PHP 缩小或转换 PDF 以进行实时预览
问题描述
问题
- 目前正在使用 PDFI + TCPDF 在 Laravel PHP 中创建实时 PDF 生成预览,以便用户可以导入基础 PDF 并在其上嵌入文本
- PDF 生成适用于所有尺寸,但大型 PDF(例如 A1 尺寸)会生成 10+ MB 的文件,该文件太大而无法返回前端进行预览
- 寻找最快和最好的方法来优化和减小 PDF 文件大小,或调整实际 PDF 尺寸以提供仅用于预览的缩小版本
TLDR
寻找建议(除了我在下面尝试过的建议),或对我尝试通过调整大小或转换为原始大 PDF 的图像文件来创建 PDF 预览文件的改进。
到目前为止我尝试过的
Imagick PDF 到图像转换- 良好的输出大小 (31mb > 700kb) 但速度很慢 (1secs > 10secs)
在使用图像创建缩小的 PDF 之前使用 Imagick 将 PDF 转换为图像是我最初的想法但是我发现 Imagick 在阅读时真的很慢PDF blob 图像(大约需要 9 秒,而 PDF 生成本身需要不到 1 秒)。代码如下
// $output === the PDF generated
$downscaleSizeFactor = $this->jsonFile->canvas['downscale_size_factor'] ?? 1;
$previewWidth = $this->size['width'] / $downscaleSizeFactor;
$previewHeight = $this->size['height'] / $downscaleSizeFactor;
$im = new Imagick;
$im->readImageBlob($output); // SLOW HERE!!!
$numPages = $im->getNumberImages();
$pdfPreview = new TCPDF($this->size["orientation"], 'mm', [$previewWidth, $previewHeight], true, 'UTF-8', false);
$pdfPreview->setPrintHeader(false);
$pdfPreview->setPrintFooter(false);
$pdfPreview->SetAutoPageBreak(false, 0);
for($i=0;$i<$numPages;$i++) {
$im->setIteratorIndex($i);
$selectedIm = $im->getImage();
$selectedIm->resizeImage($previewWidth, $previewHeight, imagick::FILTER_LANCZOS, 1, true);
$selectedIm->setImageBackgroundColor('white');
$selectedIm->setImageAlphaChannel(Imagick::ALPHACHANNEL_REMOVE);
$selectedIm->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
$selectedIm->setImageFormat('png');
$selectedIm->setImageCompressionQuality(100);
$imageString = $selectedIm->getImageBlob();
// add a page
$pdfPreview->AddPage();
// set JPEG quality
$pdfPreview->setJPEGQuality(100);
$pdfPreview->Image('@'.$imageString, 0, 0, $previewWidth, $previewHeight);
}
$im->clear();
$im->destroy();
return $pdfPreview->output('', 'S');
重新运行 FPDI + TCPDF 以生成缩小版本- 输出大小错误 (31mb > 31mb) 但速度极快 (1secs > 1.5secs)
将生成的 PDF 保存到临时文件夹,然后使用生成的 PDF 生成缩小版本,仅用于预览。这在速度方面效果很好,但它根本没有改变文件大小。从 [600 mm x 800 mm] 减小到 [10 mm x 10 mm] 根本没有减小文件大小,这很奇怪。如果有人能看到,也许我错过了一些东西。代码如下
$reducedPdf = new FpdiTcpdfCustom();
$tempPdfFile = storage_path('app/templates/pdf/temp/'.$name.'');
$pageCount = $reducedPdf->setSourceFile($tempPdfFile);
$pageNo = 1;
for ($pageNo; $pageNo <= $pageCount; $pageNo++) {
// Checks if the page is to be skipped
// Import a page from the blank by setting the
$pageId = $reducedPdf->importPage($pageNo);
// Return the size of the imported page
$size = $reducedPdf->getTemplateSize($pageId);
// Remove default header/footer
$reducedPdf->setPrintHeader(false);
$reducedPdf->setPrintFooter(false);
$reducedPdf->SetAutoPageBreak(false, 0);
// Creates the PDF page
$reducedPdf->AddPage($size['orientation'], [10,10]);
$reducedPdf->useTemplate($pageId, 0, 0, 10, 10);
}
return $reducedPdf->output('', 'S');
使用 Spatie\PdfToImage 生成图像文件- 良好的输出大小(31mb > 218kb)但速度很垃圾(1secs > 27secs 只是为了转换和保存图像)
与以前类似,希望在调整大小和嵌入之前将 PDF 转换为图像文件图像转换为 PDF 以供预览。但它非常慢,所以我什至在生成 PDF 之前就放弃了这种方法。
$tempPdf = new \Spatie\PdfToImage\Pdf(storage_path('app/templates/pdf/temp/'.$name));
$tempPdf->setCompressionQuality(10);
$tempPdf->saveImage(storage_path('app/templates/pdf/temp/'));
建议?
有没有人对改进我的尝试或实现我需要的另一种方式提出建议?
解决方案
推荐阅读
- java - 尝试节省内存是否有意义?
- python - 如何在 python 中从 Web 抓取的数据中写入 csv 文件
- python-3.x - Python3 字符串问题
- java - 尝试从多种方法获取信息
- javascript - 如何将“\\u00e2”或“\\u00ea”等字符解码为 unicode 字符?
- asp.net-web-api - Azure 移动服务客户端 InvokeApiAsync 未命中 WebAPI
- javascript - 如何制作粘性标题
- mysql - 当 CPU 使用率达到 100% 时,MySQL 会发生什么?
- jira - 如何集成 JIRA 和 Asterisk?
- angular - ViewEncapsulation.Emulated 样式被 ViewEncapsulation.(Native|ShadowDom) 组件复制到#shadow-root