多多色-多人伦交性欧美在线观看-多人伦精品一区二区三区视频-多色视频-免费黄色视屏网站-免费黄色在线

國內(nèi)最全I(xiàn)T社區(qū)平臺(tái) 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當(dāng)前位置:首頁 > php開源 > php教程 > BMP 和 JPEG

BMP 和 JPEG

來源:程序員人生   發(fā)布時(shí)間:2016-06-22 08:45:04 閱讀次數(shù):2419次

1. 甚么是 BMP
BMP 格式是最簡單,最直觀的位圖數(shù)據(jù)格式.它的思想非常樸素:
用若干個(gè)位來保存1個(gè)像素的信息,由若干個(gè)像素組成1個(gè)像素流來表達(dá)1張圖片.
通常我們會(huì)用1位(可以保存2種色彩,0 表示1種色彩,1表示另外一種,不1定是黑白,也能夠是藍(lán)綠,總之是2種),4位 - 16種色彩,8位 - 256種色彩,16位 - 65535種色彩,24位 - 2^24種色彩,32位 - 前24位和24位位圖1樣可以保存2^24種色彩,最后8位用來保存這個(gè)像素的灰度(也就是這個(gè)像素的明暗程度),可以表示256種灰度.注意,目前的顯示器在硬件上通常只能支持24位色,而且 libjpeg 也只能處理最多24位色的像素流.

對(duì)24位以下的BMP,可以引入1個(gè)"調(diào)色板"來增強(qiáng)圖片的表達(dá)能力,以8位,256色位圖作為例子:
在8位位圖中,每一個(gè)像素的信息用1個(gè)字節(jié)存儲(chǔ),那末 DIB 數(shù)據(jù)就是1個(gè) BYTE dibBuffer[] 數(shù)組, dibBuffer[0] 表示第1個(gè)像素的色彩,以此類推. 我們知道色彩是由RGB 3個(gè)份量組合而成的,編程中用 RGBQUAD 結(jié)構(gòu)表示,那末8位除以3,每一個(gè)份量只能用2位來存儲(chǔ)(不使用編碼緊縮RLE的條件下),實(shí)際能夠表現(xiàn)的色彩非常有限.現(xiàn)在我們引入1個(gè)長度為256的 RGBQUAD 類型的數(shù)組: RGBQUAD colorTable[256],我們?cè)?DBI 數(shù)組 dibBuffer[] 中不再直接寄存的每一個(gè)像素的色彩值,而是寄存該色彩值在 colorTable 中的索引,這樣就能夠充分利用 dibBuffer 中的每位的存儲(chǔ)空間.這個(gè) "colorTable" 就是 Windows 中調(diào)色板的概念. 知道了這些,就能夠理解為何24位及以上色深的位圖不需要調(diào)色板了.

2.1. BMP 文件格式和DIB
DIB就是"裝備無關(guān)位圖"的意思,我們可以理解為1個(gè)像素?cái)?shù)組,這是編程時(shí)我們需要處理的數(shù)據(jù),非常簡單,就是1個(gè)定長數(shù)組,如果是1個(gè)24位的DIB數(shù)據(jù),那末在編程時(shí)就能夠認(rèn)為是1個(gè) BYTE dibBuffer[], dibBuffer[0],dibBuffer[2],dibBuffer[2]表示第1個(gè)像素的 RGB 值(實(shí)際上是 BGR), dibBuffer[3],[4],[5] 表示第2個(gè)像素的 RGB 值,以此類推.固然我們不能直接把這個(gè) dibBuffer 數(shù)組寫到磁盤作為 BMP 文件,缺少圖片的調(diào)色板,寬,高等信息,所以我們需要1個(gè)特定的格式來存儲(chǔ) DIB 像素流.

BMP文件格式就是把DIB像素流存儲(chǔ)到磁盤是需要遵守的相干約定. 關(guān)于BMP文件格式的詳細(xì)說明在網(wǎng)上可以找到很多,比如這篇說的就很清楚: http://blog.csdn.net/lanbing510/article/details/8176231
從編程的角度來看,1個(gè)BMP文件是可以表述為以下結(jié)構(gòu):
typedef struct tagBITMAP_FILE
{
      BITMAPFILEHEADER bitmapheader;
      BITMAPINFOHEADER bitmapinfoheader;
      PALETTEENTRY palette[n]; // 調(diào)色板數(shù)據(jù)(可選,由BITMAPFILEHEADER::bOffBits計(jì)算 n 的值)
      UCHAR *dibBuffer;   // DIB 數(shù)據(jù)數(shù)組
} BITMAP_FILE;
BITMAPFILEHEADER, BITMAPINFOHEADER, PALETTEENTRY 結(jié)構(gòu)的詳細(xì)信息可以在 MSDN 中查到.

用自然語言簡單描寫1下:
文件頭 - 固定長度,表示這個(gè)文件是1個(gè) BMP 文件,版本號(hào),文件長度等,最重要的時(shí)文件頭結(jié)構(gòu)中的 bfOffBits 字段,它表示 DIB 像素流數(shù)據(jù)在文件中的偏移位置,編程時(shí),我們打開1個(gè) BMP 文件,先讀取固定長度的文件頭,在根據(jù)這個(gè)字段就能夠構(gòu)造前面說的調(diào)色板數(shù)組 RGBQUAD colorTable[] 和 DIB 數(shù)組 BYTE dibBuffer[] 了.
BMP信息頭 - 固定長度,存儲(chǔ)位圖的寬高等信息,需要注意的字段 biHeight, 如果它是正數(shù)則表示像素流的信息是倒序存儲(chǔ)的,即位圖的底下1行的像素存儲(chǔ)在前;如果它是負(fù)數(shù)則表示像素流的信息是正序存儲(chǔ)的,位圖的第1行像素存儲(chǔ)在 dibBuffer 開頭.
調(diào)色板數(shù)組 - 可選,用文件頭中的偏移地址減去文件頭和信息頭的長度就是調(diào)色板數(shù)組的長度.
DIB像素流 - 就是 dibBuffer[] 數(shù)組.
特別要注意的1點(diǎn)是,在實(shí)際編程中, 24位 DIB 數(shù)據(jù)的寄存順序是 BGR 即 dibBuffer[0] 寄存的是最后1行的第1個(gè)像素的 B 份量, dibBuffer[1] 是 G 份量, dibBuffer[2] 是 R 份量, 而 JPG 緊縮時(shí)要求輸入順序是 RGB, 所以把 dibBuffer 提供給 JPEG 緊縮器前需要處理1下, dibBuffer[i] 和 dibBuffer[i + 2] 交換,否則得到的 JPG 圖象色彩是不對(duì)的.

2.2. DDB
DDB 是"裝備相干位圖"的意思,把 DIB 數(shù)據(jù)寫入裝備以后,裝備在內(nèi)部會(huì)把 DIB 數(shù)據(jù)處理為內(nèi)部數(shù)據(jù)格式, Windows GDI 中用 HBITMAP 表述1個(gè) DDB,我們只需要調(diào)用相干的 API 就能夠了,具體細(xì)節(jié)不用理睬.

3. 甚么是 JPEG
JPEG是 DIB 數(shù)據(jù)的1種編碼規(guī)則,前面我們提到 BMP 文件,直接把 DIB 數(shù)組 dibBuffer[] 直接寫到文件中,所以BMP文件是原始的,無損失的保存了內(nèi)存中的圖象數(shù)據(jù).如果用某種算法把 dibBuffer 數(shù)組編碼緊縮,那末我們或許就沒必要把全部 dibBuffer (通常是1個(gè)很大的數(shù)組) 直接寫入文件中,從而大大節(jié)省磁盤空間. JPEG 就是這樣1種算法.

4. libjpeg
C語言實(shí)現(xiàn)的 JPEG 庫,官網(wǎng)地址: http://www.ijg.org/

4.1 編譯
我寫這篇文章的時(shí)候 JPEG 庫的版本是 jpeg⑼b,從官網(wǎng)上下載源碼 jpegsr9b.zip 解壓后,啟動(dòng)Visual Studio,進(jìn)入命令行模式,切換到 jpeg 源碼目錄,輸入: nmake /f makefile.vc 就會(huì)看到 jpeg.sln - VS工程文件出現(xiàn)了,用Visual Studio 打開編譯便可.
如果履行 nmake 命令時(shí)提示找不到 win32.mak,就編輯1下 makefile.vc 把第12行 !include 注釋掉就能夠,其實(shí) nmake /f makefile.vc 其實(shí)不是真正編譯,這是重命名了幾個(gè)文件而已.
編譯完成后得到: jpeg.lib 這就是你需要的庫文件了,再把 jconfig.h, jerror.h, jinclude.h, jmorecfg.h, jpeglib.h 復(fù)制到你的工程中就算配置完成了.

4.2 example.c
libjpeg 的使用實(shí)例在源碼包中的 example.c 文件里, 我們只要把 write_JPEG_file / read_JPEG_file 兩個(gè)函數(shù)看明白就能夠應(yīng)付大多數(shù)利用了.
 
4.3 內(nèi)存 JPG 緊縮解緊縮及其它
example.c 中的實(shí)例是使用文件io的, 用 jpeg_mem_src / jpeg_mem_dest 函數(shù)代替 jpeg_stdio_src / jpeg_stdio_dest 就能夠?qū)崿F(xiàn)內(nèi)存io了.

JPEG庫是不知道調(diào)色板之類的東西的,它只是很單純的把輸入的 DIB 像素流緊縮輸出為1個(gè)更短的輸出數(shù)據(jù)流.所以對(duì)包括了調(diào)色板的 BMP 文件,由于 DIB 數(shù)組內(nèi)保存的是調(diào)色板的索引號(hào)而其實(shí)不是色彩值,在提交給 JPEG 庫之前需要根據(jù)調(diào)色板查表構(gòu)造1個(gè)真實(shí)的包括色彩信息的 DIB 像素流,這樣 JPEG 庫才能正常工作.

====================================================================================================
附錄: 截取windows桌面,并保存為 .jpg 文件
int save_screen_to_jpeg(const char* filename, int quality) { /* * 把屏幕內(nèi)容保存為1個(gè) HBITMAP DDB */ HDC hScrnDC = CreateDC(_T("DISPLAY"), NULL, NULL, NULL); HDC hMemDC = CreateCompatibleDC(hScrnDC); // 獲得屏幕分辨率 int xScrn = GetDeviceCaps(hScrnDC, HORZRES); int yScrn = GetDeviceCaps(hScrnDC, VERTRES); // 創(chuàng)建位圖,并選中 HBITMAP hScrnBmp = CreateCompatibleBitmap(hScrnDC, xScrn, yScrn); SelectObject(hMemDC, hScrnBmp); // 復(fù)制屏幕內(nèi)容 BitBlt(hMemDC, 0, 0, xScrn, yScrn, hScrnDC, 0, 0, SRCCOPY); // 現(xiàn)在得到了1個(gè) HBITMAP DDB - hScrnBmp /* * 通過 hScrnBmp DDB 獲得 DIB 數(shù)據(jù) */ // 獲得色深 JPG 只能處理 24 位色,所以不管當(dāng)前系統(tǒng)設(shè)置的色深是多少,我們都要求 GetDIBits 函數(shù)返回 24 位的 DIB 數(shù)據(jù),同時(shí)也不需要調(diào)色板 //int colorDeepBits = GetDeviceCaps(hScrnBmp, BITSPIXEL); //if(colorDeepBits > 24) colorDeepBits = 24; int colorDeepBits = 24; // 每行像素占用的字節(jié)數(shù),每行要對(duì)齊4字節(jié). int imageRowSize = (xScrn * colorDeepBits + 31) / 32 * 4; // 分配 DIB 數(shù)組 unsigned char* dibBuffer = new unsigned char[imageRowSize * yScrn]; assert(dibBuffer); memset(dibBuffer, 0, imageRowSize * yScrn); // 清零是個(gè)好習(xí)慣 // 填充 BMP 信息頭 BITMAPINFO bmi = {0}; bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmi.bmiHeader.biWidth = xScrn; bmi.bmiHeader.biHeight = yScrn * ⑴; // JPG 緊縮需要正序的 DIB 像素流,所以要負(fù)數(shù). bmi.bmiHeader.biPlanes = 1; bmi.bmiHeader.biBitCount = colorDeepBits; bmi.bmiHeader.biCompression = BI_RGB; // 獲得 DIB 像素?cái)?shù)組(DIB_RGB_COLORS 表示獲得 RGB 值而不是調(diào)色板索引,固然24位位圖也沒有調(diào)色板) int gdiRet = GetDIBits(hMemDC, hScrnBmp, 0, yScrn, dibBuffer, &bmi, DIB_RGB_COLORS); assert(gdiRet == yScrn); assert(bmi.bmiHeader.biSizeImage == imageRowSize * yScrn); // DIB 數(shù)據(jù)已獲得,所有的 GDI 對(duì)象可以釋放了. DeleteDC(hScrnDC); DeleteDC(hMemDC); DeleteObject(hScrnBmp); /* * 把 DIB 數(shù)據(jù)緊縮為 JPG 數(shù)據(jù),用 example.c 中的代碼 */ // DIB 中色彩的寄存順序是 BGR, 而 JPG 要求的順序是 RGB, 所以要交換 R 和 B. // 由于有行對(duì)齊因素,所以逐行處理 for(int row = 0; row < yScrn; ++row) { unsigned char* rowData = dibBuffer + imageRowSize * row; for(int col = 0; col < xScrn * 3; col += 3) { unsigned char swap = rowData[col]; rowData[col] = rowData[col + 2]; rowData[col + 2] = swap; } } //把位圖數(shù)據(jù)緊縮為 jpeg struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; FILE * outfile; /* target file */ JSAMPROW row_pointer[1]; /* pointer to JSAMPLE row[s] */ int row_stride; /* physical row width in image buffer */ int image_width = xScrn; int image_height = yScrn; JSAMPLE* image_buffer = dibBuffer; // DIB buffer int image_buffer_len = imageRowSize * image_height; // DIB buffer 長度 if(fopen_s(&outfile, filename, "wb")) //if ((outfile = fopen_s(filename, "wb")) == NULL) { fprintf(stderr, "can't open %s\n", filename); assert(0); } else { /* Step 1: allocate and initialize JPEG compression object */ cinfo.err = jpeg_std_error(&jerr); /* Now we can initialize the JPEG compression object. */ jpeg_create_compress(&cinfo); /* Step 2: specify data destination (eg, a file) */ /* Note: steps 2 and 3 can be done in either order. */ jpeg_stdio_dest(&cinfo, outfile); /* Step 3: set parameters for compression */ /* First we supply a description of the input image. * Four fields of the cinfo struct must be filled in: */ cinfo.image_width = image_width; /* image width and height, in pixels */ cinfo.image_height = image_height; cinfo.input_components = 3; /* # of color components per pixel */ // 由于DIB數(shù)據(jù)是24位的,所以每一個(gè)像素占用3個(gè)字節(jié) cinfo.in_color_space = JCS_RGB; /* colorspace of input image */ /* Now use the library's routine to set default compression parameters. * (You must set at least cinfo.in_color_space before calling this, * since the defaults depend on the source color space.) */ jpeg_set_defaults(&cinfo); /* Now you can set any non-default parameters you wish to. * Here we just illustrate the use of quality (quantization table) scaling: */ jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */); /* Step 4: Start compressor */ /* TRUE ensures that we will write a complete interchange-JPEG file. * Pass TRUE unless you are very sure of what you're doing. */ jpeg_start_compress(&cinfo, TRUE); /* Step 5: while (scan lines remain to be written) */ /* jpeg_write_scanlines(...); */ /* Here we use the library's state variable cinfo.next_scanline as the * loop counter, so that we don't have to keep track ourselves. * To keep things simple, we pass one scanline per call; you can pass * more if you wish, though. */ row_stride = imageRowSize; while (cinfo.next_scanline < cinfo.image_height) { /* jpeg_write_scanlines expects an array of pointers to scanlines. * Here the array is only one element long, but you could pass * more than one scanline at a time if that's more convenient. */ row_pointer[0] = &image_buffer[cinfo.next_scanline * row_stride]; //row_pointer[0] = &image_buffer[image_buffer_len - (cinfo.next_scanline + 1) * row_stride]; (void)jpeg_write_scanlines(&cinfo, row_pointer, 1); } /* Step 6: Finish compression */ jpeg_finish_compress(&cinfo); /* After finish_compress, we can close the output file. */ fclose(outfile); /* Step 7: release JPEG compression object */ /* This is an important step since it will release a good deal of memory. */ jpeg_destroy_compress(&cinfo); } // 釋放 DIB 數(shù)組 delete []dibBuffer; return 0; }

PS: 最近1年半在忙1個(gè)項(xiàng)目,1直沒時(shí)間更新博客,也沒有回答網(wǎng)友們的發(fā)問,非常抱歉.大多數(shù)問題都是百度1下就能夠處理的,只能說抱歉了.
截屏保存為JPG其實(shí)也是我在項(xiàng)目中用到的1個(gè)小功能,由于不觸及甚么商業(yè)上的東西,就貼出來分享1下.
以后有機(jī)會(huì)我會(huì)把項(xiàng)目中的1些功能分解成可以復(fù)用的代碼,大家交換1下.


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對(duì)您的學(xué)習(xí)有所幫助,可以手機(jī)掃描二維碼進(jìn)行捐贈(zèng)
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 国产拍拍拍免费专区在线观看 | 亚洲精品人成在线观看 | 国内精品一区二区三区 | jizz在线观看18 | 日韩天天摸天天澡天天爽视频 | 免费看毛片网站 | 国产精品第1页在线播放 | 97成人在线观看 | 色人阁久久| 日韩欧美亚洲国产精品字幕久久久 | 亚洲欧美国产另类 | 欧美疯狂xxxx乱大交视频 | 欧美一级淫片漂亮的老师 | 欧洲一区 | 中文字幕日本一本二本三区 | 国产三级手机在线 | 亚洲图片另类小说 | 日本一本视频 | 国产成人精品视频一区二区不卡 | 国产一级理论免费版 | 最近在线更新中文字幕3 | jizz在亚洲 | 美美女高清毛片视频免费观看 | 精品三级国产一区二区三区四区 | 亚洲毛片视频 | 国产综合视频在线观看 | 羞羞视频在线 | 宇都宫紫苑在线播放ed2k | 国产人成精品午夜在线观看 | 欧美疯狂xxxx乱大交视频 | 国产1区2区在线观看 | 成人a级高清视频在线观看 成人a毛片高清视频 | 日本在线观 | 亚洲精品成人a在线观看 | 亚洲生活片| 日本一区不卡在线 | 欧美激情精品久久久久久久久久 | 性色va| 欧美一区二区日韩一区二区 | 欧美videos日本hd | 日本视频中文字幕 |