0. libjpeg 介紹
參考:http://zh.wikipedia.org/wiki/Libjpeg
1.使用 libjpeg 保存圖片的方法。
不多說,直接上代碼:
rgb_to_jpeg(LPRgbImage img, ** * error_flag = = jpeg_std_error(&&= fopen(filename, (f == - &= img->width; jcs.image_height = img->height; jcs.input_components = ; jcs.in_color_space = JCS_RGB; jpeg_set_defaults(&&jcs, , ); jpeg_start_compress(& (jcs.next_scanline <= img->rgb + jcs.image_width * jcs.next_scanline * &jcs, &pData, &&
**= fopen(filename, (f == cinfo.err = jpeg_std_error(&&&&= (LPRgbImage) malloc( (pRgbImage ==->width =->height =->linesize = libcfc_align_size(cinfo.image_width * ->rgb = (unsigned *) malloc(pRgbImage->linesize * (pRgbImage->rgb ==&] = pRgbImage-> (cinfo.output_scanline <] = pRgbImage->+ (cinfo.image_height - cinfo.output_scanline - ) * pRgbImage->&cinfo, row_pointer, &&
2. 問題描述
使用以上方法保存 rgb 數據到 jpeg 文件時,如果磁盤空間滿或其他原因導致不能寫文件失敗,整個進程會被結束。但我們的期望往往是磁盤空間滿時給出友好提示,而不是程序直接掛掉。
3. 問題分析
1)在開發環境上重現此問題,程序會在控制台上打印“Output file write error --- out of disk space?”,然後退出。
2)在 libjpeg 的源代碼中搜索 “Output file write error --- out of disk space?”,找到 jerror.h 文件,內容對應
JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?")。
3)可以看出,JERR_FILE_WRITE 是 libjpeg 給這個問題描述信息定義的一個編號。
4)查找 JERR_FILE_WRITE 這個編號被引用過的地方,發現有六個文件使用過這個符號(我使用的是 libjpeg9,其他版本應該也不會影響本文的分析過程)。
5)JERR_FILE_WRITE 被引用的形式為:
ERREXIT(cinfo, JERR_FILE_WRITE);
ERREXIT 是一個宏,轉到這個宏的定義,這個宏同樣的被定義在 jerror.h 中,其定義如下:
ERREXIT(cinfo,code) \->err->msg_code =*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo)))
可以看出來,ERREXIT 宏做了兩件事:
a)將編號(本文中討論的問題編號對應 JERR_FILE_WRITE)賦值給 (cinfo)->err->msg_code
b)調用 (cinfo)->err->error_exit) 回調。
cinfo 就是 初始化 libjpeg 時指定的 struct jpeg_decompress_struct。
(cinfo)->err->msg_code 是 libjpeg 處理錯誤的錯誤代碼。
(cinfo)->err->error_exit 是 libjpeg 在出現錯誤時,用來退出的回調函數。我們的程序就是這樣被退出的。
4. 解決辦法
通過分析,知道了程序退出是(cinfo)->err->error_exit 實現的,因此我們可以讓這個回調函數指針指向我們自己的函數。
並且,因為 libjpeg 會在出錯的時候給 (cinfo)->err->msg_code 一個值,之個值就是 libjpeg 定義的錯誤描述編號,非零的,所以可以在調用 libjpeg 的函數之前將這個值設置為 0,調用完成後在檢查這個時是否為 0,這樣來判斷 libjpeg 的函數調用是否成功。
5. 在 android 下的問題
遇到這個問題是因為要做一個 android 的播放器,其中解碼使用了 ffmpeg,截圖保存使用 libjpeg。本文上面描述的方法並不能完全奏效。
在 android 下保存截圖,如果使用的 sd 卡滿,導致保存圖片失敗,並不會回調我們使用 (cinfo)->err->error_exit 指定的函數。每次都會生成一個大小為 0 的文件。
通過分析,認為這事 android 寫文件時緩存機制的問題:sd 卡滿了,但寫文件是是先寫到緩存的,因此每次寫入文件都會先寫到緩存中,不會返回失敗。並且每次調用 fwrite 返回已經寫入的數據數是正確的,等到關閉文件或刷新緩存的時候,才會出錯。
為了解決這個問題,在打開文件時,將文件的緩存關閉,這樣,就能使用本文提到的方法來解決問題了。
setbuf(f, NULL);
6. 結束語
下面提供本文源代碼的完整版,代碼中使用的位圖必須是 24 位位圖,且掃描順序是自下而上的。
View Code
源代碼下載鏈接:http://files.cnblogs.com/baiynui1983/jpeg_sample.rar