zoukankan      html  css  js  c++  java
  • Look into Bitmap images

    What's a Bitmap image?

    I'm not going to explain the differences between raster and vector images, nor the difference between bitmap image with extension .bmp and jpg/png images. Herein, the bitmap refers to raster images with .bmp extension only.

    Bitmap is uncompressed, and the image is represented with arrays, namely, RGB arrays.

    What's the storage of a bitmap

    File structure of a bitmap

    • The bitmaps stored on the physical devices contains serval parts:
    1. BITMAPINFO
      1. BITMAPINFOHEADER
      2. RGBQUAD
      2. The stored data in array

    The definition are

    typedef struct tagBITMAPFILEHEADER {
        WORD  bfType;		// 2 bytes
        DWORD bfSize;		// 4 bytes
        WORD  bfReserved1;	// 2 bytes
        WORD  bfReserved2;  // 2 bytes
        DWORD bfOffBits;    // 4 bytes
    } BITMAPFILEHEADER, *LPBITMAPFILEHEADER, *PBITMAPFILEHEADER;
    
    typedef struct tagBITMAPINFO {
        BITMAPINFOHEADER bmiHeader;
        RGBQUAD          bmiColors[1];		// the '1' here is pretty tricky
    } BITMAPINFO, *LPBITMAPINFO, *PBITMAPINFO;
    
    typedef struct tagBITMAPINFOHEADER {
        DWORD biSize;			 // 8 bytes
        LONG  biWidth;			// 4 bytes
        LONG  biHeight;			// 4 bytes
        WORD  biPlanes;			//
        WORD  biBitCount;
        DWORD biCompression;
        DWORD biSizeImage;
        LONG  biXPelsPerMeter;
        LONG  biYPelsPerMeter;
        DWORD biClrUsed;
        DWORD biClrImportant;
    } BITMAPINFOHEADER, *PBITMAPINFOHEADER;
    
    typedef struct tagRGBQUAD {
        BYTE rgbBlue;
        BYTE rgbGreen;
        BYTE rgbRed;
        BYTE rgbReserved;
    } RGBQUAD;
    

    Let's use Lena.bmp as an illustration:


    (Well, this blog doesn;t support BMP image, please see the attach file)

    Open it with a hex editor, such as WinHex, and it shows

    The highlighted 14 bytes are BITMAPFILEHEADER,

    WORD bfType -> 0x4D42
    DWORD bfSize -> 0x00010438 = 66616
    WORD bfReserved1 -> 0x0000 = 0
    WORD bfReserved2 -> 0x0000 = 0
    DWORD bfOffBits -> 0x00000436 = 1078

    • bfType shows that this file is a bitmap file;
    • bfSize is the file size, as we can see below, the file sis 66,614 bytes;
    • bfReserved1 and bfReserved2 must be zeros
    • bfOffBits is the offset, in bytes, from the beginning of the BITMAPFILEHEADER structure to the bitmap bits.

    e: empcodeMFC_PICTURE_TESTLook into Bitmap images.assets1566902617332.png

    And this is the start of array data,

    seen what I mean?

    The next is BITMAPINFOHEADER, and the data are highlighted in different colors,

    and these values can be calculated as

    DWORD biSize = 0x00000028 = 40
    LONG biWidth = 0x00000100 = 256
    LONG biHeight = 0x00000100 = 256
    WORD biPlanes = 0x0001 = 1
    WORD biBitCount = 0x0008 = 8
    DWORD biCompression = 0x00000000 = 0
    DWORD biSizeImage = 0x00010002 = 65,538
    LONG biXPelsPerMeter = 0x00000B12 = 2,834
    LONG biYPelsPerMeter = 0x00000B12 = 2,834
    DWORD biClrUsed = 0x000000 = 0
    DWORD biClrImportant = 0x000000 = 0

    And we can see,

    0x0436 + 0x00010002 = 0x00010438

    1,078 + 65,538 = 66,616

    i.e.

    data_start_offset + data_length = file_end


    It's the start of data, however, since Lena.bmp is a gray image, all the three channels are same, you can find a pure red/blue image, you will find that, the bitmap is stored in [B, G, R, reserved] order, therefore, if you want to interpret in RGB mode, you should be careful with it.

    [C++]Read Bitmap File

    The following code are mainly from this website, slightly modified.

    typedef unsigned int Uint8;
    Uint8* datBuff[2] = { nullptr, nullptr }; // Header buffers
    Uint8* pixels = nullptr; // Pixels
    BITMAPFILEHEADER* bmpHeader = nullptr; // Header
    BITMAPINFOHEADER* bmpInfo = nullptr; // Info 
    
    // The file... We open it with it's constructor
    std::ifstream file(_T("Lena.bmp"), std::ios::binary);
    if (!file){
    std::cout << "Failure to open bitmap file.
    ";
    return 1;
    }
    // Allocate byte memory that will hold the two headers
    datBuff[0] = new Uint8[sizeof(BITMAPFILEHEADER)];
    datBuff[1] = new Uint8[sizeof(BITMAPINFOHEADER)];
    
    file.read((char*)datBuff[0], sizeof(BITMAPFILEHEADER));
    file.read((char*)datBuff[1], sizeof(BITMAPINFOHEADER));
    // Construct the values from the buffers
    bmpHeader = (BITMAPFILEHEADER*)datBuff[0];
    bmpInfo = (BITMAPINFOHEADER*)datBuff[1];
    // Check if the file is an actual BMP file
    if (bmpHeader->bfType != 0x4D42){
    std::cout << "File isn't a bitmap file
    ";
    return 2;
    }
    // First allocate pixel memory
    pixels = new Uint8[bmpInfo->biSizeImage];
    
    // Go to where image data starts, then read in image data
    file.seekg(bmpHeader->bfOffBits);
    file.read((char*)pixels, bmpInfo->biSizeImage);
    // First allocate pixel memory
    pixels = new Uint8[bmpInfo->biSizeImage];
    
    // Go to where image data starts, then read in image data
    file.seekg(bmpHeader->bfOffBits);
    file.read((char*)pixels, bmpInfo->biSizeImage);
    
    // Set width and height to the values loaded from the file
    int w = bmpInfo->biWidth;
    int h = bmpInfo->biHeight;
    
    // We're almost done. We have our image loaded, however it's not in the right format.
    // .bmp files store image data in the BGR format, and we have to convert it to RGB.
    // Since we have the value in bytes, this shouldn't be to hard to accomplish
    Uint8 tmpRGB = 0; // Swap buffer
    for (unsigned long i = 0; i < bmpInfo->biSizeImage; i += 3){
        tmpRGB        = pixels[i];
        pixels[i]     = pixels[i + 2];
        pixels[i + 2] = tmpRGB;
    }
    
    delete[] datBuff[0];
    delete[] datBuff[1];
    delete[] pixels;
    

    Create Bitmap Image in memory, and draw on screen

    The code is mainly from this webpage, slightly modified.

    Again, the reference are given:

    1. BITMAPINFO
    2. BITMAPINFOHEADER
    3. RGBQUAD
    4. SetDIBitsToDevice
    void CChildView::OnPaint() 
    {
    	CPaintDC dc(this); // device context for painting
    	HDC hdc = dc.m_hDC;
    
    	int nWidth = 100;
    	int nHeight = 100;
    	int nChannels = 3;
    	int nImages = 3;	// three images in a row, presented in a column
    	auto nSize = nWidth * nHeight * nChannels * nImages;
    	unsigned char* data = new unsigned char[nSize] {0};
    	//memset(data, 0xFF, nSize);
    
    
    	long split = nWidth * nHeight / 4,
    		nPixel = nWidth * nHeight;		// Pixels in an image
    	// Fill the different images for differnt channels
    	unsigned char* dat = data;
    	for (int i = 0; i < nPixel; ++i, dat += 3)		// Image 0
    		dat[0] = (i / nWidth) * (255.0 / nHeight);
    	for (int i = 0; i < nPixel; ++i, dat += 3)		// Image 1
    		dat[1] = (i / nWidth) * (255.0 / nHeight);
    	for (int i = 0; i < nPixel; ++i, dat += 3)		// Image 2
    		dat[2] = (i / nWidth) * (255.0 / nHeight);
    
    	
    
    	// Allocate enough memory for the BITMAPINFOHEADER and 256 RGBQUAD palette entries
    	// NOTE: the pallet bytes are ONLY NEEDED for color LUT images ...
    	// not needed here
    	int nColors = 0;		// In BI_RGB image, the look-up-table isn't used, so the size can be zero
    	LPBITMAPINFO lpbi = (LPBITMAPINFO) new BYTE[sizeof(BITMAPINFOHEADER)+ (nColors * sizeof(RGBQUAD))];
    	
    	// These are all the members of the bitmap header struct
    	lpbi->bmiHeader.biSize   = sizeof(BITMAPINFOHEADER); // bytes
    	lpbi->bmiHeader.biWidth  = nWidth;                   // pixels units
    	lpbi->bmiHeader.biHeight = -nHeight * 3;             // negative =  = top down; pos =
    	// origin LLeft
    	lpbi->bmiHeader.biPlanes = 1;    // must be 1
    	lpbi->bmiHeader.biBitCount = 24; // can be 32 for 4-byte pixels
    	// (Upper byte ignored)
    	lpbi->bmiHeader.biCompression = BI_RGB; // BI_RGB means uncompressed
    	lpbi->bmiHeader.biSizeImage = 0;        // size of img in bytes; 0 okay
    	// for BI_RGB
    	lpbi->bmiHeader.biXPelsPerMeter = 0;	// physical device information unavailable
    	lpbi->bmiHeader.biYPelsPerMeter = 0;    // physical device information unavailable
    	lpbi->bmiHeader.biClrUsed       = 0;	// Look-Up-Tables (LUT) only
    	lpbi->bmiHeader.biClrImportant  = 0;	// LUTs only
    
    	// Draw the image into the CRT device
    	::SetDIBitsToDevice(
    		hdc,                 // handle to DC
    		0, 0,                // x-y-coord of destination upper-left corner
    		nWidth, nHeight * 3, // width-height of source rectangle
    			                 // three images present in one column
    		0, 0,                // x-y-coord of source upper-left corner
    		0,                   // uStartScan,                                // first scan line in array
    		nHeight * 3,         // number of scan lines ...
    		data,                // array of DIB bits
    		lpbi,                // bitmap information
    		DIB_RGB_COLORS);     // RGB vs. palette indexes ... RGB means raw
    	delete[] data;
    	delete[] lpbi;
    }
    

    As we can see from the result, the array is stored in [B, G, R] sequence, and no more reserved byte is need.

    Besides, if you uncomment the memset(data, 0xFF, nSize); at the 12th line, which means you set all the other values to be 255, you'll get a more beautiful image as

    If you are a Chinese, this blog may help you.

    The source code can be found in: 链接: https://pan.baidu.com/s/12NCP1tQjtLOdDccODOwpEg 提取码: 4uka 复制这段内容后打开百度网盘手机App,操作更方便哦

  • 相关阅读:
    二维树状数组的区间加减及查询 tyvj 1716 上帝造题的七分钟
    hdu5399
    WebLogicSSL解决苹果IOS itms下载问题
    怎样封装RESTful Web Service
    ie8下面版本号(包含ie8)的浏览器不支持html5标签属性解决方式(Modernizr 2.6.2插件的使用)
    在Linux平台使用VNC连接树莓派
    合作开发——设计阶段
    HDU-1165-Eddy&#39;s research II
    Iocomp控件教程之LinearGauge--线性刻度尺控件
    VB中的排序问题 15个
  • 原文地址:https://www.cnblogs.com/troy-daniel/p/BitmapComprehension.html
Copyright © 2011-2022 走看看