Qt 将不完整的 JPEG 数据加载到 QPixMap 如何验证?
Qt load incomplete JPEG data into QPixMap how to verify?
我有一个脚本可以显示在服务器上找到的所有图像并定期检查。
有时,它会下载尚未完全上传的图像,导致半个 JPEG,下半部分为灰色。
我正在使用 qbyteAray
存储接收到的数据并加载到 QPixmap
中:
QByteArray bytes = reply->readAll(); // bytes
qDebug() << "loading pixmap" ;
qDebug() << pixmap.loadFromData(bytes);
我想检测加载是否失败并在 500 毫秒后重试,但我找不到验证像素图是否包含有效 JPG 数据的解决方案。
loadFromData
returns TRUE 但在这个方法中我得到一个警告,这是上面几行的应用程序输出:
loading pixmap
Corrupt JPEG data: premature end of data segment
true
如果像素图数据损坏,有什么方法可以check/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 数据的解码发生在名为 "libjpeg" 的外部库中,因此 Qt 类 QPixmap 和 QImage 对此不做任何事情,因为它们接收到的图像是由libjpeg。如果libjpeg给QPixmap一张图片,QPixmap就认为成功了
早在 2009 年就有人要求 Qt 对此做些什么(参见 this post),但似乎没有针对此问题采取任何措施。
这意味着你很可能是一个人,除非 QPixmap 和 QImage 在未来的版本中扩展新功能,否则你无法通过调用内部方法来验证 jpeg 图像的完整性这些类。
我会建议以下其中一项:
- 自己访问libjpeg
- 检查图像最后一行的颜色。最低行的每个像素不太可能与损坏图像的情况下的灰度相同。这取决于您的应用程序,但如果您处理自然图像(照片),那么这是我建议的解决方案。
关于损坏的 JPEG 数据有几种可能的消息:
- 损坏的 JPEG 数据:数据段过早结束
- 损坏的 JPEG 数据:标记 0xd9 之前的 12 个无关字节
- 损坏的 JPEG 数据:错误的哈夫曼代码
不幸的是,不错的 vsz 方法无法捕捉到我遇到的其他 2 个错误,因为在坏图像区域没有为这些错误使用默认灰度。
但是第一个错误比我在下面建议的尝试报告所有错误但在多线程中失败更好。
在 Qt 4.8.6 中,"Corrupt JPEG data" 错误直接发送到控制台,无法从 qt 代码中捕获它们。
不确定它什么时候改变的,但是在 Qt5.5.1 中,这些消息通过 MessageHandler,因此可以捕获它们。
在软件中只从磁盘加载图片,我用下面的来知道是哪张图片损坏了。
在 MessageHandler 中,我检测到任何 "Corrupt JPEG data" 消息并将全局变量 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,下半部分为灰色。
我正在使用 qbyteAray
存储接收到的数据并加载到 QPixmap
中:
QByteArray bytes = reply->readAll(); // bytes
qDebug() << "loading pixmap" ;
qDebug() << pixmap.loadFromData(bytes);
我想检测加载是否失败并在 500 毫秒后重试,但我找不到验证像素图是否包含有效 JPG 数据的解决方案。
loadFromData
returns TRUE 但在这个方法中我得到一个警告,这是上面几行的应用程序输出:
loading pixmap
Corrupt JPEG data: premature end of data segment
true
如果像素图数据损坏,有什么方法可以check/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 数据的解码发生在名为 "libjpeg" 的外部库中,因此 Qt 类 QPixmap 和 QImage 对此不做任何事情,因为它们接收到的图像是由libjpeg。如果libjpeg给QPixmap一张图片,QPixmap就认为成功了
早在 2009 年就有人要求 Qt 对此做些什么(参见 this post),但似乎没有针对此问题采取任何措施。
这意味着你很可能是一个人,除非 QPixmap 和 QImage 在未来的版本中扩展新功能,否则你无法通过调用内部方法来验证 jpeg 图像的完整性这些类。
我会建议以下其中一项:
- 自己访问libjpeg
- 检查图像最后一行的颜色。最低行的每个像素不太可能与损坏图像的情况下的灰度相同。这取决于您的应用程序,但如果您处理自然图像(照片),那么这是我建议的解决方案。
关于损坏的 JPEG 数据有几种可能的消息:
- 损坏的 JPEG 数据:数据段过早结束
- 损坏的 JPEG 数据:标记 0xd9 之前的 12 个无关字节
- 损坏的 JPEG 数据:错误的哈夫曼代码
不幸的是,不错的 vsz 方法无法捕捉到我遇到的其他 2 个错误,因为在坏图像区域没有为这些错误使用默认灰度。 但是第一个错误比我在下面建议的尝试报告所有错误但在多线程中失败更好。
在 Qt 4.8.6 中,"Corrupt JPEG data" 错误直接发送到控制台,无法从 qt 代码中捕获它们。 不确定它什么时候改变的,但是在 Qt5.5.1 中,这些消息通过 MessageHandler,因此可以捕获它们。
在软件中只从磁盘加载图片,我用下面的来知道是哪张图片损坏了。 在 MessageHandler 中,我检测到任何 "Corrupt JPEG data" 消息并将全局变量 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)
将打印图像信息,这很可能不是遇到损坏图像的线程...