一般要將圖片儲存成特定的檔案格式、進行壓縮的話,大部分都是直接寫到磁碟裡。不過,有的時候其實可能只是要進行壓縮,而不想寫到磁碟上(速度比較慢、而且還要再讀回來),這個時候,就必須要特別處理。
而 Independent JPEG Group 的 JPEG 函式庫(官網)目前就有提供 jpeg_mem_dest() 這個函式,可以再壓縮的時候,把資料寫到指定的記憶體空間,而不用寫到磁碟上。
如果要把相關功能包成一個函式的話,寫法大概就會像下面這樣:
std::pair<unsigned char*,unsigned long> CompressJPEG( unsigned int uWidth, unsigned int uHeight, unsigned char* pImg, int iQuality = 75 ) { std::pair<unsigned char*,unsigned long> mRes = std::make_pair( (unsigned char*)NULL, 0 ); // setup JPEG compression structure data jpeg_compress_struct jcInfo; jpeg_error_mgr jErr; // JPEG error handler jcInfo.err = jpeg_std_error ( &jErr ); // initialize JPEG compression object jpeg_create_compress( &jcInfo ); // specify data destination is memory jpeg_mem_dest( &jcInfo, &mRes.first, &mRes.second ); // image format jcInfo.image_width = uWidth; jcInfo.image_height = uHeight; jcInfo.input_components = 3; jcInfo.in_color_space = JCS_RGB; // set default compression parameters jpeg_set_defaults( &jcInfo ); // set image quality jpeg_set_quality( &jcInfo, iQuality, TRUE ); // start compressor jpeg_start_compress( &jcInfo, TRUE ); int iRowStride = jcInfo.image_width * jcInfo.input_components; while( jcInfo.next_scanline < jcInfo.image_height ) { JSAMPROW pData = &( pImg[ jcInfo.next_scanline * iRowStride ] ); jpeg_write_scanlines( &jcInfo, &pData, 1 ); } // finish compression jpeg_finish_compress( &jcInfo ); // release JPEG compression object jpeg_destroy_compress( &jcInfo ); return mRes; }
這邊要輸入的參數基本上有四個,uWidth 和 uHeight 是圖片的寬和高,pImg 則是圖片的內容(未壓縮的);最後的 iQuality 則是壓縮成 JPEG 時,所要設定的品質(0-100)。至於影像的像素格式,Heresy 這邊是寫死成三個 channel、也就是 RGB 的格式。
回傳的結果有兩種資料,這邊用 std::pair 來做簡單的包裝。裡面第一項的 unsigned char* 指到的記憶體空間,就是壓縮完的資料,而第二項的 unsigned long 數值,則是代表這個資料的長度。
而如果是要使用的話,假設有一個 unsigned char 的陣列 pImg,它的大小是 w x h 的話,那只要執行下方程式碼的第一行,就可以取得壓縮成 JPEG 的資料(pJpeg)了~
std::pair<unsigned char*,unsigned long> pJpeg = CompressJPEG( w, h, pImg, 100 ); ofstream of( "e:\\test.jpg", ios::binary ); of.write( (char*)pJpeg.first, pJpeg.second ); of.close();
而如果要驗證的話,最簡單的方法,還是把他寫出來、變成實際的檔案;這時候,只要透過 ofstrem,用 binary 的形式,整個寫出來就好了。
想請問樓主對socket有研究嗎?
目前想把這個壓縮後得到的jpeg.first傳到 android 顯示圖片
讚讚
Heresy 沒有在開發 Android 的程式。
讚讚
不好意思新手發問,想再請問那個資料長度是指壓縮完的陣列的大小嗎??
讚讚
是的
讚讚
好的,謝謝!
讚讚
[…] 的 ArrayBuffer(參考),來把 JPEG 檔的資料(Heresy 這邊是直接抓資料、在記憶體內壓縮)、直接傳遞給 JavaScript 的 client […]
讚讚
OpenCV 的 cv::encode() 好像也可以做記憶體內的壓縮
http://opencv.willowgarage.com/documentation/cpp/reading_and_writing_images_and_video.html#cv-imencode
改天來研究看看。
讚讚