【问题标题】:imagecopy fails when source image is corrupt源图像损坏时 imagecopy 失败
【发布时间】:2016-07-26 12:28:59
【问题描述】:

我编写了一个简单的 PHP 脚本来将附加信息添加到网络摄像头 JPG 文件中。它添加了带有一些文本的页眉和页脚。为此,我使用此信息创建了一个新图像,然后使用 imagecopy 将原始 JPG 复制到其中。一切正常。

网络摄像头与互联网的 wifi 连接不佳,因此通过 FTP 上传的 JPG 文件很少出现部分或损坏的情况:我可以使用 GIMP 或其他图像软件打开它,但我发现它缺少一些信息底端。发生这种情况时,上述imagecopy 似乎无法复制图像数据,并且目标图像仍然是空白(对于图像区域)。

我尝试了所有发现的方法来检查原始 JPG 是否有效:

// Check image
if (exif_imagetype($last) != IMAGETYPE_JPEG) // Not a valid jpeg
    continue;
$details = getimagesize($last);
if ($details === FALSE) // Not a valid mage
    continue;
$im = imagecreatefromjpeg($last);

但所有测试都通过了。我还补充说:

if (imagecopy($dest_image, $im, 0, $top_banner_height+1, 0, 0, $img_width, $img_heigth) === FALSE) {
   imagedestroy($im);
   imagedestroy($dest_image);
   continue;
}

但我仍然无法捕获未终止的上传。如何检查图像是否可用于 GD 处理?

编辑:这是源图像在 GIMP 中的显示方式:

这是原始上传文件的一部分。

根据要求,我使用imagecreatefromjpeg 添加了打开文件的方式。这不可能是权限问题,因为脚本在 90% 的情况下都能正常工作,只是在遇到此类图像时才会失败。

edit2:我最初认为这可能是一个并发问题,因为我每分钟都通过cron运行脚本,但是FTP上传超出了服务器控制,所以它们异步运行。因此,也许脚本在上传时正在访问文件,但我检查了一下,事实并非如此,正如我在上面写的那样,上传的文件一开始就损坏了。

edit3:建议的imagecolorat 不是解决方案(至少对于所有 情况来说不是):我刚刚发现一张可以通过测试的乱七八糟的图片. jpeginfo 说:损坏的 JPEG 数据:标记 0xd9 之前的 10839 个无关字节

【问题讨论】:

  • 图像文件本身很可能没有损坏,只是有很多未填充(因此默认值)的空白像素。权限问题或访问问题也可能干扰文件输入。您能否编辑您的问题并发布您访问文件的方式以及文件属性(例如,如果是 linux)。请记住,您的“登录用户”与计算机中的“php 用户”不同。
  • 我已经编辑了更多信息。但我 100% 确定这不是权限问题,文件正确打开 90% 次
  • 您能否检查图像文件的最后字节是否为EOI(图像结尾:FF D9)。如果没有,图像“可能有问题”。您可以自己重写该文件的最后一个字节,然后运行脚本。
  • 另一个重要的一点是实际检查您的服务器配置。我的猜测是,您的服务器配置为在开始上传图像之前分配空间,因此当发生这种空间分配时,它会充满“空白”空间,这些空间被解释为您看到的灰色区域。 ImageCreateFromString 可能是你在这里寻找的魔法。
  • @Maxxer 如果您查看 imagecreatefromstring 函数的 gd 源代码,您会看到它确实会检查正确的图像标题,但是在对此进行更多研究时,我发现这是可能的有visually corrupted images which are valid。如您所见,有几种方法可以解决这个问题。

标签: php gd


【解决方案1】:

感谢大家的建议,但最后我找到了另一种可能的方法。

如上所述,在other answers 中,命令行工具jpeginfo -c filename 检查图像是否为有效的jpeg,打印警告或错误(以及返回码!= 0)。所以这是迄今为止最精确的解决方案,但涉及到外部命令。

在 PHP 方面似乎没有完美检查,同样对应的Imagick::valid 也没有对完整图像执行有效性检查。

在那very same page 有另一个建议的解决方案:

// check for the existence of the EOI segment header at the end of the file
$file = fopen($image_file, "r");
if (0 !== fseek($file, -2, SEEK_END) || "\xFF\xD9" !== fread($file, 2)) {
    // jpeg is not valid
    fclose($file);
    return FALSE;
}

效果很好,但仅适用于未完成的图像(第一种情况)。 edit 3 中发布的示例仍然通过了此测试。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-09
    相关资源
    最近更新 更多