Imagick设JPEG格式仍生成PDF:单页PDF异常问题求助
问题:单页PDF生成PDF文件而非JPG缩略图,多页PDF正常
使用Imagick为自定义管理工具中上传的PDF生成JPG缩略图,已调用setImageFormat('jpeg'),但仅单页PDF会生成PDF文件,多页PDF则可正常生成JPG缩略图。
相关代码
public function generateCopies() { if (empty($this->copyPathFormats)) { return True; } if (! is_array($this->copyPathFormats)) { throw new \InvalidArgumentException('Asset::copyPathFormat must be an array. '.gettype($this->copyPathFormats).' provided.'); } foreach ($this->copyPathFormats as $key => $copyPathFormat) { if ($key === 'finder') { continue; } $path = $this->basePath.$this->pathParamSubstitution($copyPathFormat, $this->pathParam); if (! (is_dir($path) || mkdir($path, 0777, True))) { throw new \RuntimeException($path.' could not be found or created.'); } $img = new \Imagick($this->path.$this->name); $img->setImageCompressionQuality( 89 ); $copyName = $this->name; $format = $img->getImageFormat(); if ($format === 'PDF') { $img = new \Imagick(); $img->setResolution(150,150); $img->readImage($this->path.$this->name.'[0]'); $img->setImageCompressionQuality( 70 ); $img = $img->flattenImages(); $img->setImageFormat('jpeg'); $filename = pathinfo($this->name, PATHINFO_FILENAME); $copyName = $filename.'.jpg'; } $geometry = $img->getImageGeometry(); $width = $geometry['width'] >= $geometry['height'] ? $this->copySizeConstraints[$key] : 0; $height = $geometry['height'] > $geometry['width'] ? $this->copySizeConstraints[$key] : 0; if ($img->scaleImage($width,$height,False) !== True) { \RuntimeException('Cannot resize the image.'); } if ($img->writeImage($path.$copyName) !== True) { throw new \RuntimeException('Cannot write the resized copy to '.$path.$this->name); } $img->destroy(); } return True; }
问题原因
核心问题是PDF判断逻辑不可靠:
- 加载多页PDF时,
$img->getImageFormat()返回PDF,进入处理分支,正确生成JPG缩略图。 - 加载单页PDF时,Imagick会自动将PDF渲染为图像对象,此时
$img->getImageFormat()返回渲染后的图像格式(如JPEG),而非PDF,导致跳过PDF处理分支。最终使用原PDF文件名写入,且未设置JPG格式,因此生成的还是PDF文件。
另外代码存在疏漏:\RuntimeException('Cannot resize the image.')仅创建了异常对象,未抛出,无法终止错误流程。
修复方案
1. 改用可靠的PDF识别方式
不要依赖Imagick加载后的格式判断,直接基于原文件属性识别PDF:
方式一:基于文件后缀判断
// 替换原有的$format判断逻辑 $fileExtension = strtolower(pathinfo($this->name, PATHINFO_EXTENSION)); if ($fileExtension === 'pdf') { $img->destroy(); // 销毁之前创建的Imagick对象,避免资源泄漏 $img = new \Imagick(); $img->setResolution(150,150); $img->readImage($this->path.$this->name.'[0]'); $img->setImageCompressionQuality( 70 ); $img = $img->flattenImages(); $img->setImageFormat('jpeg'); $filename = pathinfo($this->name, PATHINFO_FILENAME); $copyName = $filename.'.jpg'; }
方式二:基于MIME类型判断(更准确)
// 替换原有的$format判断逻辑 $finfo = new \finfo(FILEINFO_MIME_TYPE); $mimeType = $finfo->file($this->path.$this->name); if ($mimeType === 'application/pdf') { $img->destroy(); // 销毁之前创建的Imagick对象,避免资源泄漏 $img = new \Imagick(); $img->setResolution(150,150); $img->readImage($this->path.$this->name.'[0]'); $img->setImageCompressionQuality( 70 ); $img = $img->flattenImages(); $img->setImageFormat('jpeg'); $filename = pathinfo($this->name, PATHINFO_FILENAME); $copyName = $filename.'.jpg'; }
2. 修复未抛出的异常
将Resize失败的代码修改为:
if ($img->scaleImage($width,$height,False) !== True) { throw new \RuntimeException('Cannot resize the image.'); }
内容的提问来源于stack exchange,提问作者awvickers
相关产品推荐
相关产品推荐

