PHP Imagick在将PDF转换为图像时挂起整个服务器
我使用PHP上的扩展名Imagick将PDF文件转换为图像,具体来说是PNG文件。 转换过程中,整个服务器始终挂起。我所做的是上传一堆PDF文件,循环浏览它和它的页面,将其转换为图像 这是代码PHP Imagick在将PDF转换为图像时挂起整个服务器,php,imagick,Php,Imagick,我使用PHP上的扩展名Imagick将PDF文件转换为图像,具体来说是PNG文件。 转换过程中,整个服务器始终挂起。我所做的是上传一堆PDF文件,循环浏览它和它的页面,将其转换为图像 这是代码 foreach ($uploaded_file as $key => $value) { $upload_file_path = $upload_path.'/'.$value->name; $imagick = new Imagick(); $imagick->setRes
foreach ($uploaded_file as $key => $value) {
$upload_file_path = $upload_path.'/'.$value->name;
$imagick = new Imagick();
$imagick->setResourceLimit(6, 1);
$imagick->setResolution(300, 300);
$imagick->readImage($upload_file_path);
$pages = $imagick->getNumberImages();
for ($x=0; $x<$pages; $x++) {
$imagick->readImage($upload_file_path.'['.$x.']');
$imagick->setImageFormat('png');
$imagick->writeImage($image_path.'/page-'.$x.'.png');
}
$imagick->clear();
$imagick->destroy();
}
foreach($key=>value){
$upload_file_path=$upload_path.'/'.$value->name;
$imagick=新的imagick();
$imagick->setResourceLimit(6,1);
$imagick->setResolution(300300);
$imagick->readImage($upload\u file\u path);
$pages=$imagick->getNumberImages();
对于($x=0;$xreadImage($upload_file_path.['.$x.]');
$imagick->setImageFormat('png');
$imagick->writeImage($image_path./page-'.$x..png');
}
$imagick->clear();
$imagick->destroy();
}
转换正在进行中,我无法访问服务器上的其他站点,转换时间太长。请提供帮助。谢谢!根据PDF的内容,转换可能确实非常繁重。您对此无能为力 您已经尝试将线程总数降低到2个,但是仍然需要考虑内存、I/O延迟和CPU资源,并且您不知道服务器是否可以使用两个以上的线程 您可以尝试使用
nice
和ionice
,降低正在运行进程的I/O和CPU优先级,如果它们可用。您需要一个合适的平台(Linux、BSD或类似平台),并访问nice
和ionice
工具;您需要一个专用的可执行PHP进程(可能不是FastCGI),并能够查询其PID
在Linux系统上,您可能会尝试将转换外包到ImageMagick二进制文件,并将其包装在nice
和ionice
中,以使转换变得简单而缓慢
另一种可能性是看你是否可以使用ghostscript来代替Imagick。将PDF转换为PNG的速度更快,你可以试试
我为您制作了一个示例程序:
#!/usr/bin/env php
<?php
require __DIR__ . '/vendor/autoload.php';
use Jcupitt\Vips;
for ($i = 1; $i < count($argv); $i++) {
$image = Vips\Image::newFromFile($argv[$i]);
$n_pages = $image->get("n-pages");
echo($argv[$i] . " has " . $n_pages . " pages\n");
for ($n = 0; $n < $n_pages; $n++) {
echo(" rendering page " . $n . " ...\n");
$page = Vips\Image::newFromFile($argv[$i], [
"dpi" => 300,
"page" => $n,
# this enables image streaming
"access" => "sequential"
]);
$page->writeToFile($argv[$i] . "_page_" . $n . ".png");
}
}
因此,它在32秒内生成了58个PNG,最大需要110mb的ram。它不创建任何临时文件——110mb覆盖了所有内容
png是一种非常慢的文件格式。如果改为保存为jpg,则需要6秒左右的时间
我尝试了你的imagick代码的一个版本:
#!/usr/bin/env php
<?php
for ($i = 1; $i < count($argv); $i++) {
$imagick = new Imagick();
$imagick->setResourceLimit(6, 1);
$imagick->setResolution(300, 300);
$imagick->readImage($argv[$i]);
$pages = $imagick->getNumberImages();
echo($argv[$i] . " has " . $pages . " pages\n");
for ($x = 0; $x < $pages; $x++) {
echo(" rendering page " . $x . " ...\n");
$imagick->readImage($argv[$i] . "[" . $x . "]");
$imagick->setImageFormat("png");
$imagick->writeImage($argv[$i] . "_page_" . $x . ".png");
}
$imagick->clear();
$imagick->destroy();
}
220秒(几乎慢了7倍)和260mb的内存。内存的使用并不是全部——在300 DPI的情况下,imagick将在/tmp中为每个页面生成一个65mb的文件,因此它总共需要大约5gb的存储空间。我想分享我的发现和一个解决方案,我认为这是很有见地的 我注意到,每页创建一个新的
imagick
实例要比尝试读取整个文件,然后让它1)读取页面数量,2)让它在所有页面上迭代快得多
我只想要PDF文件的前10页。当我有一个50页的PDF文件时(大多数只是文本,只有450KB),你以何种方式阅读这个文件真的很重要
通过这种方式,它将从第一页开始阅读,并尝试阅读到10页。如果少于10个页面,只要imagick抛出错误,它就会意识到它已经到达页面的末尾,并停止迭代
让我对我的其他尝试有更多的了解
getNumberImages()
和setIteratorIndex()
设置循环并读取各个页面。对于imagick来说,阅读整本书需要很长时间,甚至还没有开始处理所有的页面然而,这在我的测试中已经花费了10秒,只是为了阅读页数。这就是我使用上述方法的原因。您使用了多少pdf文件,平均有多少页?您在pdf中的阅读密度为300,是默认密度(72)的4倍多。因此,使用默认密度时,文件大小将增加16倍。如果您的PDF文件是大英寸,那么您可能超过了可用的RAM。有关处理大型图像的信息,请参阅。@admcfajn我有一个模板,其中我上载了32个PDF文件,共有95页,另一个模板包含95页。@fmw42是的,我正在以300的密度对其进行转换,以便在浏览器放大时图像质量不会下降。我试试你的建议。Thanks@fmw42顺便说一句,我使用了Imagick的函数setResourceLimit(),因为我读到它解决了我的问题,所以我想还有更多。我不确定使用ionice是否合适,因为我需要上传的文件在上传后进行转换。据我所知,ionice就像一个cron作业管理器,而且,没有ghostscript,Imagick无法读取PDF文件,所以我想我已经在使用它了。谢谢,我将尝试这个库,我使用PNG是因为当我转换为JPEG时,即使我更改了背景颜色,一些页面也会得到一个完整的黑色页面。在libvips跟踪器上打开一个问题如果你发现一个PDF不起作用,我会好奇地看到:我一次更新了一个页面的示例。这意味着它将适用于更改文档中页面大小的PDF。您好,我在windows上安装libvips时遇到了困难。我得到了windows二进制文件,我目前被困在如何使用PHP中,我不知道把这些二进制文件放在哪里。我需要复制php文件夹中的文件吗?顺便说一句,我使用的是xamppSorry,php VIP现在不能在windows上工作,粘合层还没有移植:修复起来应该不难,但需要有人自愿。
#!/usr/bin/env php
<?php
for ($i = 1; $i < count($argv); $i++) {
$imagick = new Imagick();
$imagick->setResourceLimit(6, 1);
$imagick->setResolution(300, 300);
$imagick->readImage($argv[$i]);
$pages = $imagick->getNumberImages();
echo($argv[$i] . " has " . $pages . " pages\n");
for ($x = 0; $x < $pages; $x++) {
echo(" rendering page " . $x . " ...\n");
$imagick->readImage($argv[$i] . "[" . $x . "]");
$imagick->setImageFormat("png");
$imagick->writeImage($argv[$i] . "_page_" . $x . ".png");
}
$imagick->clear();
$imagick->destroy();
}
$ /usr/bin/time -f %M:%e ../convert-imagick.php nipguide.pdf
nipguide.pdf has 58 pages
rendering page 0 ...
...
rendering page 57 ...
255640:223.26
$im->pingImage($tempFile);
$nrOfPages = $im->getNumberImages();