基于libjpeg保存jpg图像或者读取图像时,特别是再存储大尺寸图像时,一个问题特别突出。即图像存储明明毁损了,可是调用存储的函数直接再控制台输出警告信息,可是没有返回值或者异常可供捕获。形成毁损的缘由不明。只能推测是libjpeg多线程存储问题。其中图像存在 JWRN_JPEG_EOF 问题时特别致命。由于图像从某一个节点以后信息所有无效。如下是最终算法可以捕获的毁损。算法
JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file")多线程
JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code")ide
JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines")函数
JWRN_JPEG_EOF是核心要解决的问题。 后俩者是最后优化代码时剩余部分比较复杂,时间有限,保留代码顺带检测。优化
动手解决以前思路:基于libjpeg库,屏蔽掉无关代码,将警告改成异常抛出。捕获并产生相应记录信息。由于是提早终止,所以期待直接从文件头获取文件长度和实际文件长度比较,直接获得断定。spa
实际解决思路:线程
1.借鉴opencv的库进行libjpeg从新改写。指针
2.将libjpeg里面一些C代码更改成C++代码,并消除一些与检测无关代码,提升检测效率。code
3.跟踪JWRN_JPEG_EOF 出现位置,梳理先后代码。发现动手前的思路存在缺失。并不能直接获取文件长度进行比较。实际jpg判断该问题是基于段,每次循环前断定当前读取字节数 < 该段字节总数。是的话一次读取固定长度(jpg代码有具体数值)。当读取到字节数目<固定长度,就会进行断定 抛出俩种异常其中一种 就是“JWRN_JPEG_EOF”。 原始libjpg代码以下:blog
1 METHODDEF(boolean) 2 fill_input_buffer (j_decompress_ptr cinfo) 3 { 4 my_src_ptr src = (my_src_ptr) cinfo->src; 5 size_t nbytes; 6 7 nbytes = JFREAD(src->infile, src->buffer, INPUT_BUF_SIZE); 8 9 if (nbytes <= 0) { 10 if (src->start_of_file) /* Treat empty input file as fatal error */ 11 ERREXIT(cinfo, JERR_INPUT_EMPTY); 12 WARNMS(cinfo, JWRN_JPEG_EOF); 13 /* Insert a fake EOI marker */ 14 src->buffer[0] = (JOCTET) 0xFF; 15 src->buffer[1] = (JOCTET) JPEG_EOI; 16 nbytes = 2; 17 } 18 19 src->pub.next_input_byte = src->buffer; 20 src->pub.bytes_in_buffer = nbytes; 21 src->start_of_file = FALSE; 22 23 return TRUE; 24 }
1 METHODDEF(boolean) 2 fill_mem_input_buffer (j_decompress_ptr cinfo) 3 { 4 static const JOCTET mybuffer[4] = { 5 (JOCTET) 0xFF, (JOCTET) JPEG_EOI, 0, 0 6 }; 7 8 /* The whole JPEG data is expected to reside in the supplied memory 9 * buffer, so any request for more data beyond the given buffer size 10 * is treated as an error. 11 */ 12 WARNMS(cinfo, JWRN_JPEG_EOF); 13 14 /* Insert a fake EOI marker */ 15 16 cinfo->src->next_input_byte = mybuffer; 17 cinfo->src->bytes_in_buffer = 2; 18 19 return TRUE; 20 }
4.找到查错代码后更改自定义代码。我理解不够没有从新书写代码,而是经过剥离出来的opencv的jpeg库调用。而后跟踪执行路径,把执行路径中的函数标记出来,从新写成本身的函数,而后调用。
5.最终效果:使用opencv读取图片会报 JWRN_JPEG_EOF,我这边也会报。执行时间:16000*8192彩色图像,用imread执行时间3~5s,用我更改后的libjpeg库只须要0.2~0.3s(这边耗时主要霍夫编解码上面。由于指针遍历有部分再霍夫编解码上,赶时间没有细究。若是消除的话就是 10ms之内级别操做)。
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2019-05-10这样直接改某些状况下会触发野指针。暂不清楚引发得缘由。由于此时有问题的图片能打开,能看。不肯定是真的文件存在问题,仍是写的算法有问题。因此最好加异常捕获代码。