Qt如何将不完整的JPEG数据加载到QPixMap中并进行验证?

4
我有一个脚本,可以显示服务器上找到的所有图像并定期检查。有时,它会下载一个尚未完全上传的图像,导致下半部分呈灰色的不完整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

有没有办法检查/验证 pixmap 是否存在损坏的数据?

解决方案

如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;

如果没有直接的方法来做到这一点(我不使用 QPixMap,所以不清楚),一个办法是安装一个消息处理器来捕获 qDebug、qCritical 等消息,并在消息处理器中处理失败情况。 - drescherjm
你是在谈论Qt可能存在的一个bug(数据确实无效,像素图被清除,但loadFromData返回true),还是在说关于“损坏的JPEG数据”的警告是虚假的? - peppe
我想说的是,Qt把半满的JPEG文件视为成功接受。 - Vincent Duprez
2个回答

4
以下是对损坏的JPEG数据可能出现的几种消息的翻译:
  • 损坏的JPEG数据:数据段过早结束
  • 损坏的JPEG数据:标记0xd9之前有12个无关字节
  • 损坏的JPEG数据:错误的哈夫曼编码
在处理不良图像区域时,使用“nice vsz”方法无法捕获我遇到的另外两个错误。但是,与我下面提出的尝试报告所有错误相比,它对于第一个错误更好,但在多线程中失败。
在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)的线程将打印图像信息,但这很可能不是遇到损坏图片的那个线程...


2
JPEG数据的解码发生在外部库"libjpeg"中,因此Qt类QPixmap和QImage对此不做任何处理,它们接收到的是由libjpeg解码的图像。如果libjpeg给QPixmap一个图像,那么QPixmap就认为它是成功的。
早在2009年,有人要求Qt对此进行处理(请参见此帖子),但似乎在这个问题上没有做什么。
这意味着你很可能是自己解决问题,除非QPixmap和QImage在未来的版本中增加新功能,否则你无法通过调用这些类中的方法来验证JPEG图像的完整性。
我建议采取以下措施之一:
  • 自己访问libjpeg
  • 检查图像最后一行的颜色。每个像素都是与灰色相同的颜色的可能性很小,这取决于你的应用程序,但如果你处理自然图像(照片),那么这是我建议的解决方案。

这是一个不错的技巧,使用最后一行。如果你有这些代码行闲置在某处,能否将它们添加到你的答案中呢? - Vincent Duprez
我不知道这些像素实际上是什么样子的。然而,在图像损坏的情况下,你可以通过查看pixmap.toImage().pixel(x,y)来检查它们,然后稍后使用该值。 - vsz
对于信息和其他内容,pixel返回的值是一个带有alpha通道+RGB的无符号整数,无效jpg像素的值为4286611584,这对应于ARGB中的“FF808080”,我将尝试底部左侧、底部右侧和一些底部中间像素。真实图像可能会失效,但这种情况非常不太可能。 - Vincent Duprez
我承认我的这个建议是一个非常丑陋的hack,但我的回答重点是Qt没有提供现成的解决方案。直接访问libjpeg可能更优雅,但我怀疑它是否更具有未来性。 - vsz

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接