Qt加载不完整的JPEG数据到QPixMap如何验证



我有一个脚本,显示在服务器上找到的所有图像并定期检查。有时,它会下载一张尚未完全上传的图像,结果是半张JPEG,下半部分是灰色的。

我使用qbyteAray来存储接收到的数据,并在QPixmap中加载:

QByteArray bytes = reply->readAll();  // bytes
qDebug() << "loading pixmap" ; 
qDebug() << pixmap.loadFromData(bytes);

我想检测加载是否失败,并在500毫秒后重试,但我找不到一个解决方案来验证像素图是否包含有效的JPG数据。loadFromData返回TRUE,但在这个方法中,我得到一个警告,这是上面行的应用程序输出:

loading pixmap
Corrupt JPEG data: premature end of data segment
true

是否有任何方法来检查/bool如果像素图已损坏的数据?

解决方案

正如vsz所建议的,如果图像是自然图像而不是图形,那么下一行的像素不太可能是无效JPG的确切灰度。因此,有可能通过方法中的这些行来确定图像是否有效:

QImage img = pixmap.toImage();
    if(  img.pixel(img.width()-1,img.height()-1 )  ==  4286611584   &&  img.pixel(img.width()/2,img.height()-1 )  ==  4286611584  &&  img.pixel(0,img.height()-1 )  ==  4286611584  ) return false; //invalid color : 4286611584  (default gray jpg)
    else return true;

关于损坏的JPEG数据有几种可能的消息:

  • 损坏的JPEG数据:数据段过早结束
  • 损坏的JPEG数据:标记0xd9之前有12个多余的字节
  • 损坏的JPEG数据:坏的霍夫曼代码

好的vsz方式将不幸地无法捕获我遇到的另外2个错误,因为在坏图像区域中没有默认的灰色用于这些错误。但是对于第一个错误,它比我下面建议的尝试报告所有错误要好,但在多线程中失败。

在Qt 4.8.6中,"损坏的JPEG数据"错误直接发送到控制台,没有办法从Qt代码中捕获它们。不确定是什么时候更改的,但在Qt5.5.1中,这些消息经过MessageHandler,因此可以捕获它们。

在软件中只从磁盘加载图片,我使用以下方法来知道哪个图片损坏了。在MessageHandler中,我检测到任何"损坏的JPEG数据"消息,并将全局变量corrupt_jpg_detected设置为true。

if(msg.contains("Corrupt JPEG data"))
  setCorrupt_jpg_detected(&corrupt_jpg_detected, true);

然后在读取图像的代码中,我添加了以下内容:

QImage img(path_to_my_image) //read image file => will sent "Corrupt JPEG data" error if image corrupted
if(corrupt_jpg_detected) "code to print in log file / inform user of image corruption, can include path_to_my_image" 

这有一个很强的弱点,如果您使用多线程加载图片(例如使用QtConcurrent::mapped),那么测试if(corrupt_jpg_detected)的第一个线程将打印图像信息,这很可能不是遇到损坏图像的线程…

JPEG数据的解码发生在称为"libjpeg"的外部库中,因此Qt类QPixmap和QImage对此不做任何事情,因为它们接收到由libjpeg解码的图像。如果libjpeg给QPixmap一个图像,那么QPixmap认为它是成功的。

早在2009年就有人请求Qt对此做点什么(见这篇文章),但似乎没有针对这个问题做任何事情。

这意味着您很有可能是自己的,除非QPixmap和QImage将在未来的版本中扩展新的特性,否则您不能仅仅通过调用这些类中的方法来验证jpeg图像的完整性。

我的建议是:

  • 自己访问libjpeg
  • 检查图像最后一行的颜色。最低行的每个像素不太可能与损坏图像的情况下的灰度相同。这取决于你的应用程序,但如果你处理自然图像(照片),那么这是我建议的解决方案。

最新更新