Digital Image Processing Assignment II

Main Contents

  • Image binarization;
  • Binary image erosion;
  • Binary image dilation;
  • Binary image opening;
  • Binary image closing.

Step One: Define Some Functions

Here we define a function that generate a blank grayscale image from a given image,

void gen_gray(BITMAP *bmImg, BITMAP *bmGray) {
    BITMAPINFOHEADER *bmiHeader = &bmImg->bmInfo->bmiHeader;
    bmGray->bmHeader = bmImg->bmHeader;
    bmGray->bmInfoSize = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) << 8);
    bmGray->bmInfo = (BITMAPINFO *) malloc(bmGray->bmInfoSize);
    bmGray->bmInfo->bmiHeader = *bmiHeader;
    bmGray->bmInfo->bmiHeader.biBitCount = 8;
    for (int16_t i = 0; i < 256; ++i) {
        RGBQUAD *rgb = &bmGray->bmInfo->bmiColors[i];
        rgb->rgbBlue = i;
        rgb->rgbGreen = i;
        rgb->rgbRed = i;
        rgb->rgbReserved = 0;
    }
    init_bmp(bmGray);
    bmGray->bmHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + bmGray->bmInfoSize;
    bmGray->bmHeader.bfSize = bmGray->bmHeader.bfOffBits + (bmGray->bmBytesPerRow * bmiHeader->biHeight);
}

and a function that change a color image into grayscale.

void color2gray(BITMAP *bmImg, BITMAP *bmGray) {
    BITMAPINFOHEADER *bmiHeader = &bmImg->bmInfo->bmiHeader;
    gen_gray(bmImg, bmGray);
    uint8_t minY = 255, maxY = 0;
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg->bmBytesPerRow + w * bmImg->bmBytesPerPel;
            uint8_t *B = &bmImg->bmData[pos];
            uint8_t *G = &bmImg->bmData[pos + 1];
            uint8_t *R = &bmImg->bmData[pos + 2];
            uint8_t Y = adjust(0.299 * *R + 0.587 * *G + 0.114 * *B);
            if (Y < minY) {
                minY = Y;
            }
            if (Y > maxY) {
                maxY = Y;
            }
        }
    }
    // rearrange gray indensity
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg->bmBytesPerRow + w * bmImg->bmBytesPerPel;
            uint8_t *B = &bmImg->bmData[pos];
            uint8_t *G = &bmImg->bmData[pos + 1];
            uint8_t *R = &bmImg->bmData[pos + 2];
            uint8_t Y = adjust(0.299 * *R + 0.587 * *G + 0.114 * *B);
            uint32_t _pos = h * bmGray->bmBytesPerRow + w * bmGray->bmBytesPerPel;
            bmGray->bmData[_pos] = adjust(255. * (Y - minY) / (maxY - minY));
        }
    }
}

Step Two: Change Gray to Binary

In order to binarize the image, we need determine a threshold, and change pixels whose grayscale is below the threshold to black, and the others to white. But how to find the optimal threshold? There’s an excellent algorithm called Otsu’s method, which, in brief, maximize inter-class variance.

void gray2binary(BITMAP *bmGray, BITMAP *bmBinary) {
    BITMAPINFOHEADER *bmiHeader = &bmGray->bmInfo->bmiHeader;
    gen_gray(bmGray, bmBinary);
    double *cnt = (double *) malloc(1 << 16);
    memset(cnt, 0, 1 << 16);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmGray->bmBytesPerRow + w * bmGray->bmBytesPerPel;
            ++cnt[bmGray->bmData[pos]];
        }
    }
    double omegaK = 0, muK = 0, muT = 0, maxB = 0;
    uint8_t threshold = 0;
    for (int16_t k = 0; k < 256; ++k) {
        cnt[k] /= bmiHeader->biHeight * bmiHeader->biWidth;
        muT += k * cnt[k];
    }
    for (int16_t k = 0; k < 256; ++k) {
        omegaK += cnt[k];
        muK += k * cnt[k];
        double sigmaK = (muT * omegaK - muK) * (muT * omegaK - muK) / omegaK / (1 - omegaK);
        if (maxB < sigmaK) {
            maxB = sigmaK;
            threshold = k;
        }
    }
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmGray->bmBytesPerRow + w * bmGray->bmBytesPerPel;
            bmBinary->bmData[pos] = bmGray->bmData[pos] < threshold ? 0 : 255;
        }
    }
}

Step Three: Erosion and Dilation

Let’s say that white is the foreground and black is the background. Assume you have a solid circle, and you can only place it on white pixels, which means the circle shouldn’t cover the black pixels. We make the available area where the center can be put white and the others black, and get a new image—the result of erosion.

void erode(BITMAP *bmBinary, BITMAP *bmErosion, uint32_t border) {
    BITMAPINFOHEADER *bmiHeader = &bmBinary->bmInfo->bmiHeader;
    gen_gray(bmBinary, bmErosion);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmBinary->bmBytesPerRow + w * bmBinary->bmBytesPerPel; 
            uint8_t flag = 255;
            for (uint32_t _h = h - border; _h <= h + border; ++_h) {
                if (_h >= 0 && _h < bmiHeader->biHeight) {
                    uint32_t delta = border - abs(h - _h);
                    for (uint32_t _w = w - delta; _w <= w + delta; ++_w) {
                        if (_w >= 0 && _w < bmiHeader->biWidth) {
                            uint32_t _pos = _h * bmBinary->bmBytesPerRow + _w * bmBinary->bmBytesPerPel;
                            flag &= bmBinary->bmData[_pos];
                        }
                    }
                }
            }
            bmErosion->bmData[pos] = flag;
        }
    }
}

This time, you want to put the center of the circle on white pixels regardless of whether other points lie on black pixels. We make the area that can be covered by the circle white and the others black. This is what dilation do. Surprisingly, the code is very very similar with erosion.

void dilate(BITMAP *bmBinary, BITMAP *bmDilation, uint32_t border) {
    BITMAPINFOHEADER *bmiHeader = &bmBinary->bmInfo->bmiHeader;
    gen_gray(bmBinary, bmDilation);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmBinary->bmBytesPerRow + w * bmBinary->bmBytesPerPel; 
            uint8_t flag = 0;
            for (uint32_t _h = h - border; _h <= h + border; ++_h) {
                if (_h >= 0 && _h < bmiHeader->biHeight) {
                    uint32_t delta = border - abs(h - _h);
                    for (uint32_t _w = w - delta; _w <= w + delta; ++_w) {
                        if (_w >= 0 && _w < bmiHeader->biWidth) {
                            uint32_t _pos = _h * bmBinary->bmBytesPerRow + _w * bmBinary->bmBytesPerPel;
                            flag |= bmBinary->bmData[_pos];
                        }
                    }
                }
            }
            bmDilation->bmData[pos] = flag;
        }
    }
}

Step Four: Opening and Closing

In fact, opening operation and closing operation are just the combination of the two operations we mentioned above, the only difference is the order. Opening operation is an erosion followed by a dilation, while closing operation is the reverse.

Visually speaking, opening operation makes the gaps between black pixels disappeared, and closing operation makes the gaps between white pixels disappeared.

Note that these two operations are both idempotent, which means performing one of them multiple times is equivalent to performing it one time.

Digital Image Processing Assignment I

Main Contents

  • Read a color bmp;
  • RGB->YUV;
  • Color to gray: gray=Y in YUV color space;
  • Rearrange gray intensity to lie between [0,255];
  • Write a grayscale bmp;
  • Change the luminance value Y;
  • YUV->RGB;
  • Write a color bmp.

Step One: BMP File Structure

A common BMP file is comprised of four part: image file header, image information header, palette and image data.

The image file header is a struct whose length is 14 bytes. Here gives its definition,

typedef struct tagBITMAPFILEHEADER {
    WORD bfType;  
    DWORD bfSize;  
    WORD bfReserved1;  
    WORD bfReserved2; 
    DWORD bfOffBits; 
} BITMAPFILEHEADER;

and the explanation for every variable.

  • bfType: must always be set to ‘BM’ to declare that this is a .bmp-file;
  • bfSize: specifies the size of the file in bytes;
  • bfReserved1: must always be set to zero;
  • bfReserved2: must always be set to zero;
  • bfOffBits: specifies the offset from the beginning of the file to the bitmap data.

The image information header is also a struct, while its length is 40 bytes. The definition

typedef struct tagBITMAPINFOHEADER {
    DWORD biSize;     
    LONG biWidth;    
    LONG biHeight;    
    WORD biPlanes;    
    WORD biBitCount   
    DWORD biCompression;  
    DWORD biSizeImage;   
    LONG biXPelsPerMeter;  
    LONG biYPelsPerMeter;  
    DWORD biClrUsed;  
    DWORD biClrImportant; 
} BITMAPINFOHEADER;

The explanation

  • biSize: number of bytes to define BITMAPINFORHEADER structure;
  • biWidth: image width (number of pixels);
  • biHeight: image height (number of pixels), note that if it’s a positive number, the image is inverted, otherwise upright;
  • biPlanes: number of planes, should always be 1;
  • biBitCount: bits per pixel, which may be 1, 4, 8, 16, 24, 32;
  • biCompression: compression type, only non-compression(BI_RGB) is discussed here;
  • biSizeImage: image size with bytes, when biCompression is BI_RGB, biSizeImage is 0;
  • biXPelsPerMeter: horizontal resolution, pixels per meter;
  • biYPelsPerMeter: vertical resolution, pixels per meter;
  • biClrUsed: number of color indices used in the bitmap, when it’s 0, all the palette items are used;
  • biClrImportant: number of important color indices for image display, when it’s 0, all items are important.

The palette has a series of RGBQUADs, which is defined like this.

typedef struct tagRGBQUAD {
    uint8_t rgbBlue;
    uint8_t rgbGreen;
    uint8_t rgbRed;
    uint8_t rgbReserved;
} RGBQUAD;

Note that the order of the color is blue, green, and red, not the reverse. The number of RGBQUADs is decided by biBitCount and biClrUsed.

Next we need to define BITMAPINFO.

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[1];
} BITMAPINFO;

As we know nothing about the number of RGBQUADs an image uses, the BITMAPINFO should be defined as a pointer so that right amount of memory can be allocated to it.

The image data contains color of all pixels, and every biBitCount bit(s) represents a pixel.

At last, we define a struct to storage a full BMP image.

typedef struct tagBITMAP {
    BITMAPFILEHEADER bmHeader;
    BITMAPINFO *bmInfo;
    uint32_t bmInfoSize;
    uint32_t bmBytesPerRow;
    uint8_t bmBytesPerPel;
    uint8_t *bmData;
} BITMAP;

When defining the two structs, we need to add a line #pragma pack(push, 1) to avoid struct padding.

Step Two: Read/Write a BMP File

A BMP file is a binary file, so we need to add "b" to the second parameter when using fopen.

Another important thing is that the number of bytes in one row must always be adjusted to fit into the border of a multiple of four, and we need to calculate how many bytes are there in one row.

For convenience, we define an initialize function, which receives bmHeader and bmInfo, and initializes other variables.

// given bmHeader and bmInfo, initialize others
void init_bmp(BITMAP *bmImg) {
    BITMAPINFOHEADER *bmiHeader = &(bmImg->bmInfo->bmiHeader);
    bmImg->bmBytesPerRow = ((bmiHeader->biWidth * bmiHeader->biBitCount + 31) >> 5) << 2;
    bmImg->bmBytesPerPel = bmiHeader->biBitCount >> 3;
    bmImg->bmData = (uint8_t *) malloc(bmImg->bmBytesPerRow * bmiHeader->biHeight);
}

The read function is showed below.

// read a BMP from file
void read_bmp(BITMAP *bmImg, char *filepath) {
    FILE *fiInImg = fopen(filepath, "rb");
    BITMAPINFOHEADER bmiHeader;
    fread(&(bmImg->bmHeader), sizeof(BITMAPFILEHEADER), 1, fiInImg);
    fread(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, fiInImg);
    // if biBitCount is less than 16, use all the palette, otherwise do not use palette
    if (bmiHeader.biBitCount < 16) {
        bmImg->bmInfoSize = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) << bmiHeader.biBitCount);
    } else {
        bmImg->bmInfoSize = sizeof(BITMAPINFOHEADER);
    }
    bmImg->bmInfo = (BITMAPINFO *) malloc(bmImg->bmInfoSize);
    bmImg->bmInfo->bmiHeader = bmiHeader;
    if (bmiHeader.biBitCount < 16) {
        fread(bmImg->bmInfo->bmiColors, sizeof(RGBQUAD), 1 << bmiHeader.biBitCount, fiInImg);
    }
    init_bmp(bmImg);
    fread(bmImg->bmData, bmImg->bmBytesPerRow, bmiHeader.biHeight, fiInImg);
    fclose(fiInImg);
}

The write function looks similar with the read function.

// write a BMP to file
void write_bmp(BITMAP *bmImg, char *filepath) {
    FILE *fiOutImg = fopen(filepath, "wb");
    fwrite(&(bmImg->bmHeader), sizeof(BITMAPFILEHEADER), 1, fiOutImg);
    fwrite(bmImg->bmInfo, bmImg->bmInfoSize, 1, fiOutImg);
    fwrite(bmImg->bmData, bmImg->bmBytesPerRow, bmImg->bmInfo->bmiHeader.biHeight, fiOutImg);
    fclose(fiOutImg);
}

Step Three: Change Color to Gray

To make things easier, we define a function to duplicate a BMP file,

// duplicate a BMP
void copy_bmp(BITMAP *bmDes, BITMAP *bmSrc) {
    memcpy(bmDes, bmSrc, sizeof(BITMAP));
    bmDes->bmInfo = (BITMAPINFO *) malloc(bmSrc->bmInfoSize);
    memcpy(bmDes->bmInfo, bmSrc->bmInfo, bmSrc->bmInfoSize);
    BITMAPINFOHEADER *bmiHeader = &(bmSrc->bmInfo->bmiHeader);
    bmDes->bmData = (uint8_t *) malloc(bmSrc->bmBytesPerRow * bmiHeader->biHeight);
    memcpy(bmDes->bmData, bmSrc->bmData, bmSrc->bmBytesPerRow * bmiHeader->biHeight);
}

and a function to make sure the RGB value of a pixel lie between [0, 255].

// make RGB value legal
uint8_t adjust(double val) {
    int16_t ret = (int16_t) (val + 0.5);
    return ret < 0 ? 0 : ret > 255 ? 255 : ret;
}

We need to change RGB to YUV first, as the grayscale is determined by Y value. The formula is

$$\begin{bmatrix} 0.299 & 0.587 & 0.114 \\ -0.147 & -0.289 & 0.436 \\ 0.615 & -0.515 & -0.100 \end{bmatrix} \times \begin{bmatrix} R \\ G \\ B \end{bmatrix} = \begin{bmatrix} Y \\ U \\ V \end{bmatrix}$$

    // calculate YUV value
    double *bmYUV = (double *) malloc(sizeof(double) * bmImg.bmBytesPerRow * bmiHeader->biHeight);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            uint8_t *B = &bmImg.bmData[pos];
            uint8_t *G = &bmImg.bmData[pos + 1];
            uint8_t *R = &bmImg.bmData[pos + 2];
            bmYUV[pos] = 0.299 * *R + 0.587 * *G + 0.114 * *B;
            bmYUV[pos + 1] = -0.147 * *R - 0.289 * *G + 0.436 * *B;
            bmYUV[pos + 2] = 0.615 * *R - 0.515 * *G - 0.100 * *B;
        }
    }

To change color to gray, we can simply make the R, G and B value of a pixel equal to its Y value. It would be more complex if we want to change it into an image with biBitCount equal to 8, because we need to set the palette manually.

One more step, rearrange gray intensity to lie between [0,255]. It’s just a math problem. So the code

    // color to gray
    BITMAP bmGray;
    bmGray.bmHeader = bmImg.bmHeader;
    bmGray.bmInfoSize = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) << 8);
    bmGray.bmInfo = (BITMAPINFO *) malloc(bmGray.bmInfoSize);
    bmGray.bmInfo->bmiHeader = *bmiHeader;
    bmGray.bmInfo->bmiHeader.biBitCount = 8;
    for (int i = 0; i < 256; ++i) {
        RGBQUAD *rgb = &(bmGray.bmInfo->bmiColors[i]);
        rgb->rgbBlue = i;
        rgb->rgbGreen = i;
        rgb->rgbRed = i;
        rgb->rgbReserved = 0;
    }
    init_bmp(&bmGray);
    uint8_t min = 255, max = 0;
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            double *Y = &bmYUV[pos];
            if (*Y < min) {
                min = *Y;
            }
            if (*Y > max) {
                max = *Y;
            }
        }
    }
    // rearrange gray indensity
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            double *Y = &bmYUV[pos];
            uint32_t _pos = h * bmGray.bmBytesPerRow + w * bmGray.bmBytesPerPel;
            bmGray.bmData[_pos] = adjust(255 * (*Y - min) / (max - min));
        }
    }

Step Four: Change the Luminance

The luminance is depend on Y value, too. What we need to do is just changing the Y value and applying the inverse formula below.

$$\begin{bmatrix} 1.000 & 0.000 & 1.140 \\ 1.000 & -0.3946 & -0.5805 \\ 1.000 & 2.032 & -0.0005 \end{bmatrix} \times \begin{bmatrix} Y \\ U \\ V \end{bmatrix} = \begin{bmatrix} R \\ G \\ B \end{bmatrix}$$

And the code is simple.

    // change luminance
    BITMAP bmLight, bmDark;
    copy_bmp(&bmLight, &bmImg);
    copy_bmp(&bmDark, &bmImg);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            double *Y = &bmYUV[pos];
            double *U = &bmYUV[pos + 1];
            double *V = &bmYUV[pos + 2];
            bmLight.bmData[pos] = adjust(*Y + 25 + 2.032 * *U - 0.0005 * *V);
            bmLight.bmData[pos + 1] = adjust(*Y + 25 - 0.3946 * *U - 0.5805 * *V);
            bmLight.bmData[pos + 2] = adjust(*Y + 25 + 1.140 * *V);
            bmDark.bmData[pos] = adjust(*Y - 50 + 2.032 * *U - 0.0005 * *V);
            bmDark.bmData[pos + 1] = adjust(*Y - 50 - 0.3946 * *U - 0.5805 * *V);
            bmDark.bmData[pos + 2] = adjust(*Y - 50 + 1.140 * *V);
        }
    }

Step Five: Complete Source Code

bmp.h

#ifndef _BMP_H_
#define _BMP_H_

#include <stdint.h>

#pragma pack(push, 1) // avoid struct padding

typedef struct tagBITMAPFILEHEADER {
    uint16_t bfType;
    uint32_t bfSize;
    uint16_t bfReserved1;
    uint16_t bfReserved2;
    uint32_t bfOffBits;
} BITMAPFILEHEADER;

typedef struct tagBITMAPINFOHEADER {
    uint32_t biSize;
    int32_t biWidth;
    int32_t biHeight;
    uint16_t biPlanes;
    uint16_t biBitCount;
    uint32_t biCompression;
    uint32_t biSizeImage;
    int32_t biXPelsPerMeter;
    int32_t biYPelsPerMeter;
    uint32_t biClrUsed;
    uint32_t biClrImportant;
} BITMAPINFOHEADER;

typedef struct tagRGBQUAD {
    uint8_t rgbBlue;
    uint8_t rgbGreen;
    uint8_t rgbRed;
    uint8_t rgbReserved;
} RGBQUAD;

typedef struct tagBITMAPINFO {
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[1];
} BITMAPINFO;

typedef struct tagBITMAP {
    BITMAPFILEHEADER bmHeader;
    BITMAPINFO *bmInfo;
    uint32_t bmInfoSize;
    uint32_t bmBytesPerRow;
    uint8_t bmBytesPerPel;
    uint8_t *bmData;
} BITMAP;

#pragma pack(pop)

#endif

bmp.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "bmp.h"

// given bmHeader and bmInfo, initialize others
void init_bmp(BITMAP *bmImg) {
    BITMAPINFOHEADER *bmiHeader = &(bmImg->bmInfo->bmiHeader);
    bmImg->bmBytesPerRow = ((bmiHeader->biWidth * bmiHeader->biBitCount + 31) >> 5) << 2;
    bmImg->bmBytesPerPel = bmiHeader->biBitCount >> 3;
    bmImg->bmData = (uint8_t *) malloc(bmImg->bmBytesPerRow * bmiHeader->biHeight);
}

// read a BMP from file
void read_bmp(BITMAP *bmImg, char *filepath) {
    FILE *fiInImg = fopen(filepath, "rb");
    BITMAPINFOHEADER bmiHeader;
    fread(&(bmImg->bmHeader), sizeof(BITMAPFILEHEADER), 1, fiInImg);
    fread(&bmiHeader, sizeof(BITMAPINFOHEADER), 1, fiInImg);
    // if biBitCount is less than 16, use all the palette, otherwise do not use palette
    if (bmiHeader.biBitCount < 16) {
        bmImg->bmInfoSize = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) << bmiHeader.biBitCount);
    } else {
        bmImg->bmInfoSize = sizeof(BITMAPINFOHEADER);
    }
    bmImg->bmInfo = (BITMAPINFO *) malloc(bmImg->bmInfoSize);
    bmImg->bmInfo->bmiHeader = bmiHeader;
    if (bmiHeader.biBitCount < 16) {
        fread(bmImg->bmInfo->bmiColors, sizeof(RGBQUAD), 1 << bmiHeader.biBitCount, fiInImg);
    }
    init_bmp(bmImg);
    fread(bmImg->bmData, bmImg->bmBytesPerRow, bmiHeader.biHeight, fiInImg);
    fclose(fiInImg);
}

// duplicate a BMP
void copy_bmp(BITMAP *bmDes, BITMAP *bmSrc) {
    memcpy(bmDes, bmSrc, sizeof(BITMAP));
    bmDes->bmInfo = (BITMAPINFO *) malloc(bmSrc->bmInfoSize);
    memcpy(bmDes->bmInfo, bmSrc->bmInfo, bmSrc->bmInfoSize);
    BITMAPINFOHEADER *bmiHeader = &(bmSrc->bmInfo->bmiHeader);
    bmDes->bmData = (uint8_t *) malloc(bmSrc->bmBytesPerRow * bmiHeader->biHeight);
    memcpy(bmDes->bmData, bmSrc->bmData, bmSrc->bmBytesPerRow * bmiHeader->biHeight);
}

// write a BMP to file
void write_bmp(BITMAP *bmImg, char *filepath) {
    FILE *fiOutImg = fopen(filepath, "wb");
    fwrite(&(bmImg->bmHeader), sizeof(BITMAPFILEHEADER), 1, fiOutImg);
    fwrite(bmImg->bmInfo, bmImg->bmInfoSize, 1, fiOutImg);
    fwrite(bmImg->bmData, bmImg->bmBytesPerRow, bmImg->bmInfo->bmiHeader.biHeight, fiOutImg);
    fclose(fiOutImg);
}

// make RGB value legal
uint8_t adjust(double val) {
    int16_t ret = (int16_t) (val + 0.5);
    return ret < 0 ? 0 : ret > 255 ? 255 : ret;
}

int main(int argc, char *argv[]) {
    // read bmp file
    BITMAP bmImg;
    read_bmp(&bmImg, "original.bmp");
    BITMAPINFOHEADER *bmiHeader = &(bmImg.bmInfo->bmiHeader);

    // calculate YUV value
    double *bmYUV = (double *) malloc(sizeof(double) * bmImg.bmBytesPerRow * bmiHeader->biHeight);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            uint8_t *B = &bmImg.bmData[pos];
            uint8_t *G = &bmImg.bmData[pos + 1];
            uint8_t *R = &bmImg.bmData[pos + 2];
            bmYUV[pos] = 0.299 * *R + 0.587 * *G + 0.114 * *B;
            bmYUV[pos + 1] = -0.147 * *R - 0.289 * *G + 0.436 * *B;
            bmYUV[pos + 2] = 0.615 * *R - 0.515 * *G - 0.100 * *B;
        }
    }

    // color to gray
    BITMAP bmGray;
    bmGray.bmHeader = bmImg.bmHeader;
    bmGray.bmInfoSize = sizeof(BITMAPINFOHEADER) + (sizeof(RGBQUAD) << 8);
    bmGray.bmInfo = (BITMAPINFO *) malloc(bmGray.bmInfoSize);
    bmGray.bmInfo->bmiHeader = *bmiHeader;
    bmGray.bmInfo->bmiHeader.biBitCount = 8;
    for (int i = 0; i < 256; ++i) {
        RGBQUAD *rgb = &(bmGray.bmInfo->bmiColors[i]);
        // to prove that the palette works well, play a small trick
        rgb->rgbBlue = (i >> 4) << 4;
        rgb->rgbGreen = (i >> 4) << 4;
        rgb->rgbRed = (i >> 4) << 4;
        rgb->rgbReserved = 0;
    }
    init_bmp(&bmGray);
    uint8_t min = 255, max = 0;
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            double *Y = &bmYUV[pos];
            if (*Y < min) {
                min = *Y;
            }
            if (*Y > max) {
                max = *Y;
            }
        }
    }
    // rearrange gray indensity
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            double *Y = &bmYUV[pos];
            uint32_t _pos = h * bmGray.bmBytesPerRow + w * bmGray.bmBytesPerPel;
            bmGray.bmData[_pos] = adjust(255 * (*Y - min) / (max - min));
        }
    }
    write_bmp(&bmGray, "gray.bmp");

    // change luminance
    BITMAP bmLight, bmDark;
    copy_bmp(&bmLight, &bmImg);
    copy_bmp(&bmDark, &bmImg);
    for (uint32_t h = 0; h < bmiHeader->biHeight; ++h) {
        for (uint32_t w = 0; w < bmiHeader->biWidth; ++w) {
            uint32_t pos = h * bmImg.bmBytesPerRow + w * bmImg.bmBytesPerPel;
            double *Y = &bmYUV[pos];
            double *U = &bmYUV[pos + 1];
            double *V = &bmYUV[pos + 2];
            bmLight.bmData[pos] = adjust(*Y + 25 + 2.032 * *U - 0.0005 * *V);
            bmLight.bmData[pos + 1] = adjust(*Y + 25 - 0.3946 * *U - 0.5805 * *V);
            bmLight.bmData[pos + 2] = adjust(*Y + 25 + 1.140 * *V);
            bmDark.bmData[pos] = adjust(*Y - 50 + 2.032 * *U - 0.0005 * *V);
            bmDark.bmData[pos + 1] = adjust(*Y - 50 - 0.3946 * *U - 0.5805 * *V);
            bmDark.bmData[pos + 2] = adjust(*Y - 50 + 1.140 * *V);
        }
    }
    write_bmp(&bmLight, "light.bmp");
    write_bmp(&bmDark, "dark.bmp");

    return 0;
}

Optimized Input and Output in C++

Background

C++标准库<iostream>中的cin, cout相比<cstdio>中的scanf, printf要方便许多,但速度也较为缓慢。在输入输出的数据类型不是很特殊时,可以使用以下代码来代替cin, cout(要包含<cctype>, <cstdio>,不要包含<iostream>)。

Code

class InputStream {
private:
  static int const BUFFER_SIZE = 10000000;
  char *buffer;

public:
  InputStream() {
    buffer = new char[BUFFER_SIZE]();
    fread(buffer, sizeof(char), BUFFER_SIZE, stdin);
  }
  InputStream &operator>>(int &n) {
    for (; *buffer < '0' || *buffer > '9'; ++buffer)
      ;
    for (n = 0; *buffer >= '0' && *buffer <= '9';
         (n *= 10) += *(buffer++) - '0')
      ;
    return *this;
  }
  InputStream &operator>>(char &c) {
    for (; !isprint(*buffer) || *buffer == ' '; ++buffer)
      ;
    c = *(buffer++);
    return *this;
  }
  InputStream &operator>>(char *s) {
    char *t = s;
    for (; !isprint(*buffer) || *buffer == ' '; ++buffer)
      ;
    for (; isprint(*buffer) && *buffer != ' '; *(t++) = *(buffer++))
      ;
    *t = '\0';
    return *this;
  }
} cin;

class OutputStream {
private:
  static int const BUFFER_SIZE = 10000000;
  char *buffer, *cur;

public:
  OutputStream() { buffer = cur = new char[BUFFER_SIZE](); }
  ~OutputStream() { fwrite(buffer, sizeof(char), cur - buffer, stdout); }
  OutputStream &operator<<(int const &n) {
    for (sprintf(cur, "%d", n); *cur; ++cur)
      ;
    return *this;
  }
  OutputStream &operator<<(char const &c) {
    *(cur++) = c;
    return *this;
  }
  OutputStream &operator<<(char *s) {
    for (char *t = s; *t; *(cur++) = *(t++))
      ;
    return *this;
  }
} cout;

static char const endl = '\n';

Mathjax in WordPress

Background

Mathjax允许我们在Blog中插入漂亮的数学公式。WordPress里有许多Mathjax插件,但大多都不尽如人意,总是缺少这样那样的功能。下面介绍一种不使用插件的方法,可以近乎完美地解决问题。

Steps

  • 点击仪表盘左侧“外观”选项卡中的“编辑”选项,进入“编辑主题”;
  • 在右侧的“主题文件”中,选择“主题页眉”(header.php);
  • 找到其中的<head>标签,在下面插入如下代码;

<script type="text/x-mathjax-config">
  MathJax.Hub.Config({
    extensions: ["tex2jax.js"],
    jax: ["input/TeX", "output/HTML-CSS"],
    tex2jax: {
      inlineMath: [ ['\$','\$'], ["\\(","\\)"] ],
      displayMath: [ ['\$\$','\$\$'], ["\\[","\\]"] ],
      processEscapes: true
    },
    "HTML-CSS": { fonts: ["TeX"] }
  });
</script>

<script type="text/javascript" src="https://cdn.bootcss.com/mathjax/2.7.4/latest.js?config=TeX-MML-AM_CHTML"></script>

  • 点击更新文件,完成后回到站点,查看Mathjax效果;
  • 根据自己的需要修改配置(以上代码适用于大部分情况)。

Known Issues

  • 每次更换主题后需要重复以上步骤。

Archlinux Installation Guide

准备工作

镜像下载 && 启动盘制作

镜像文件可以直接从官方网站上下载。
下载完成后,Windows用户可以用Ultraiso制作启动盘,Linux用户可以用dd制作启动盘,具体如下:

# dd if=*.iso of=/dev/sd*

其中if表示输入文件,of表示输出文件,/dev/sd*表示U盘。具体参数要根据实际情况确定。

开始安装 && 分区操作

使用U盘启动系统,进入命令行界面后,用以下命令查看硬盘状态:

# parted -l

从硬盘列表中找到希望安装到的硬盘,假设为/dev/sda,那么可以用以下命令进行分区操作:

# parted /dev/sda

一般来说,Linux只需要分出/主分区和swap分区,当然也可以根据个人需要分出/home/boot等分区。对于内存在2GiB以下的电脑,建议将swap分区的大小设为实际内存大小的2倍,其他电脑只需设为实际内存大小。关于parted的使用,这里不再赘述。
分区后需进行格式化。假设将/dev/sda1设为/主分区,/dev/sda2设为/home分区,/dev/sda3设为swap分区,执行以下命令来格式化:

# mkfs.ext4 /dev/sda1
# mkfs.ext4 /dev/sda2
# mkswap /dev/sda3
# swapon /dev/sda3

将分区挂载到Linux根目录下:

# mount /dev/sda1 /mnt
# mkdir /mnt/home
# mount /dev/sda2 /mnt/home

如果BIOS是UEFI的,还需要用parted创建EFI分区(假设为/dev/sda4),并进行以下操作:

# mkfs.vfat -F32 /dev/sda4
# mkdir -p /mnt/boot/efi
# mount /dev/sda4 /mnt/boot/efi

准备工作完成。

安装系统

安装过程中需要网络,可以使用以下命令连接WiFi:

# wifi-menu

有线网的连接方法将在后面提及。
使用以下命令编辑/etc/pacman.conf(vim使用方法不再赘述):

# vim /etc/pacman.conf

在文件最后添加一段:

[archlinuxcn]
SigLevel = Optional TrustAll
Server   = https://mirrors.ustc.edu.cn/archlinuxcn/$arch

接着,需要将/etc/pacman.d/mirrorlist中非China的源删去(因为外国源访问速度较慢)。
使用以下命令更新源:

# pacman -Syy

安装基本系统:

# pacstrap /mnt base base-devel

此过程持续时间较长,需要耐心等待。
生成fstab:

# genfstab -U -p /mnt >> /mnt/etc/fstab

切换主目录:

# arch-chroot /mnt /bin/bash

这时命令提示符会发生变化。首先安装vim:

pacman -S vim

接下来设置语言环境,创建/etc/locale.conf,添加一行LANG=en_US.UTF-8,修改/etc/locale.gen,把en_US.UTF-8 UTF-8zh_CN.GBK GBKzh_CN.UTF-8 UTF-8zh_CN GB2312前面的注释去掉。使用以下命令更新语言环境:

# locale-gen

设置时间:

# rm /etc/localtime
# ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
# hwclock --systohc --utc

设置主机名以及root密码:

# vim /etc/hostname
# passwd

安装net工具:

# pacman -S net-tools dnsutils inetutils iproute2 dialog

安装GRUB:

For BIOS:

# pacman -S grub os-prober
# grub-install --recheck /dev/sda
# grub-mkconfig -o /boot/grub/grub.cfg

For UEFI:

# pacman -S dosfstools grub efibootmgr
# grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=arch_grub --recheck
# grub-mkconfig -o /boot/grub/grub.cfg

卸载分区:

# exit
# umount /mnt/home
# umount /mnt
# reboot

安装系统完成。重启后,输入root和密码即可进入系统。

基本配置

配置有线网络:
使用ifconfig查看网卡信息,假设有线网卡名为eth0。创建/etc/systemd/network/eth0.network,添加以下内容:

[Match]
Name=eth0
[Network]
Address=192.168.1.100/24
Gateway=192.168.1.1

创建/etc/systemd/resolved.conf,添加以下内容:

[Resolve]
DNS=114.114.114.114

执行以下命令:

# rm -f /etc/resolv.conf
# ln -s /run/systemd/resolve/resolv.conf /etc/resolv.conf
# systemctl disable netctl.service
# systemctl enable systemd-networkd.service
# systemctl enable systemd-resolved.service
# reboot

即可正常使用有线网。
添加用户:

# useradd -m -k /etc/skel -G users,wheel YourName
# passwd YourName

安装Xorg以及字体:

# pacman -S xorg xorg-server xorg-xinit xorg-twm xtrem ttf-dejavu wqy-zenhei wqy-microhei

安装触摸板驱动:

# pacman -S xf86-input-libinput xorg-xinput
# libinput list-devices

安装显卡驱动:

For Intel:

# pacman -S xf86-video-intel

For Nvidia:

# pacman -S xf86-video-nouveau

For ATi:

# pacman -S xf86-video-ati

安装压缩软件:

# pacman -S p7zip zip unzip rar unrar

安装NTFS支持:

# pacman -S ntfs-3g

同步网络时间:

# pacman -S ntp
# systemctl enable ntpd

安装桌面环境:

For Gnome:

# pacman -S gnome gnome-extra gdm
# systemctl enable gdm

For KDE:

# pacman -S plasma sddm
# systemctl enable sddm

For Deepin:

# pacman -S deepin deepin-extra lightdm

For i3wm:

# pacman -S i3-gaps i3status i3blocks i3lock

配置startx:
编辑/etc/X11/xinit/xinitrc,注释掉以下内容:

twm &
xclock -geometry 50x50-1+1 &
xterm -geometry 80x50+494+51 &
xterm -geometry 80x20+494-0 &
exec xterm -geometry 80x66+0+0 -name login

添加以下内容:

For Gnome:

exec gnome-session

For KDE:

exec startkde

For i3wm:

exec i3

保存后就可以用startx进入桌面了。

后续优化

yaourt

/etc/pacman.conf最后添加一段:

[archlinuxcn]
SigLevel = Optional TrustAll
Server   = https://mirrors.ustc.edu.cn/archlinuxcn/$arch

更新源,然后执行:

# pacman -S yaourt

fcitx

使用以下命令安装fcitx:

# pacman -S fcitx fcitx-im fcitx-libpinyin

创建~/.xprofile,添加一段:

export GTK_IM_MODULE=fcitx
export QT_IM_MODULE=fcitx
export XMODIFIERS="@im=fcitx"

然后使用fcitx设置进行配置即可。

chromium

使用以下命令安装chromium以及flash插件:

# pacman -S chromium pepper-flash

总结

Archlinux的核心理念就是KISS原则(Keep It Simple, Stupid)。这个原则就是让系统保持简单。而这里的简单却不是所谓的开箱即用(out-of-the-box),而是让默认的软件与配置“能少就少”。Arch还拥有非常强大的包管理器pacman以及社区用户软件仓库AUR,软件几乎应有尽有。Arch的wiki也是所有发行版中做的最好最全面的。它还支持滚动升级,一次安装可以永久使用。当然,更重要的是用户可以从中学到很多:用户几乎是从零开始安装整个系统,包括硬盘分区、设置语言及时区、安装软件包等等。只有亲手操作一遍后,才会了解Linux发行版的安装方式。另外,因为所有软件都是用户自己安装的,如果某个软件出了问题,可以自己尝试调试,或者卸载重装,这并不会影响操作系统本身。

My .conkyrc

use_spacer right
use_xft yes
font Microsoft YaHei:size=8
xftfont Microsoft YaHei:size=8
override_utf8_locale yes
update_interval 1.0
own_window yes
own_window_type desktop
own_window_transparent yes
#own_window_hints undecorated,below,sticky,skip_taskbar,skip_pager
own_window_argb_visual yes
own_window_argb_value 120
double_buffer yes
minimum_size 206 5
maximum_width 400
draw_shades yes
draw_outline no
draw_borders no
draw_graph_borders no
default_color ffffff
default_shade_color 000000
default_outline_color 000000
alignment top_right
gap_x 5
gap_y 35
cpu_avg_samples 2
uppercase no # set to yes if you want all text to be in uppercase

TEXT
${font Microsoft YaHei:style=Bold:pixelsize=22}${alignc}${time %H:%M:%S}
${font Microsoft YaHei:pixelsize=16}${alignc}${time %b%d日星期%a}${alignc}
${color #ffa200}${hr 2}
${font Microsoft YaHei:pixelsize=12}
${color #00ffcf}主机名:${color #00ffcf} $alignr$nodename
${color #00ffcf}内核: ${color #00ffcf}$alignr$kernel
${color #00ffcf}已运行时间: ${color #00ffcf}$alignr$uptime
${color #ffd700}${stippled_hr 1}
${font Microsoft YaHei:pixelsize=12}
${color #00ff1e}CPU 0: ${cpu cpu0}% $alignr$acpitemp°C(T)
${color #dcff82}${cpubar 8 cpu0}
${color #00ff1e}CPU 1: ${cpu cpu1}% 
${color #dcff82}${cpubar 8 cpu1}
${color #00ff1e}CPU占用:$alignr CPU%
${color #ddaa00} ${top name 1}$alignr${top cpu 1}
${color lightgrey} ${top name 2}$alignr${top cpu 2}
${color lightgrey} ${top name 3}$alignr${top cpu 3}
${color #ffd700}${stippled_hr 1}$color
${font Microsoft YaHei:pixelsize=12}
${color #00ff1e}SAM: $mem $alignr${color #db7093}$memperc%
${color #78af78}${membar 8}
${color #00ff1e}SWAP: $swap $alignr ${color #db7093}$swapperc%
${color #78af78}${swapbar 8}
${color #00ff1e}内存占用: $alignr MEM% 
${color #ddaa00} ${top_mem name 1}$alignr ${top_mem mem 1}
${color lightgrey} ${top_mem name 2}$alignr ${top_mem mem 2}
${color lightgrey} ${top_mem name 3}$alignr ${top_mem mem 3}
${color #ffd700}${stippled_hr 1}$color
${font Microsoft YaHei:pixelsize=12}
${color #00ff1e}硬盘读取速度:${alignr}${diskio_read}
${color #00ff1e}硬盘写入速度:${alignr}${diskio_write}
${color #ffd700}${stippled_hr 1}$color
${font Microsoft YaHei:pixelsize=12}
${color #00ff1e}网络 $alignr ${color #00ff1e}IP地址: ${color DDAA00}${addr enp3s0}
${voffset 1}${color #98c2c7} 上传: ${color #db7093}${upspeed enp3s0}/s ${alignr}${color #98c2c7}总共: ${color #db7093}${totalup enp3s0}
${voffset 1}${color #98c2c7} 下载: ${color #ddaa00}${downspeed enp3s0}/s ${alignr}${color #98c2c7}总共: ${color #ddaa00}${totaldown enp3s0}
${font Microsoft YaHei:pixelsize=12}
${color #ffa200}${hr 2}

Limits in C

Limits on Integer Constants

Constant Meaning Value
CHAR_BIT Number of bits in the smallest variable that is not a bit field. 8
SCHAR_MIN Minimum value for a variable of type signed char. –128
SCHAR_MAX Maximum value for a variable of type signed char. 127
UCHAR_MAX Maximum value for a variable of type unsigned char. 255 (0xff)
CHAR_MIN Minimum value for a variable of type char. –128; 0 if /J option used
CHAR_MAX Maximum value for a variable of type char. 127; 255 if /J option used
MB_LEN_MAX Maximum number of bytes in a multicharacter constant. 5
SHRT_MIN Minimum value for a variable of type short. –32768
SHRT_MAX Maximum value for a variable of type short. 32767
USHRT_MAX Maximum value for a variable of type unsigned short. 65535 (0xffff)
INT_MIN Minimum value for a variable of type int. –2147483648
INT_MAX Maximum value for a variable of type int. 2147483647
UINT_MAX Maximum value for a variable of type unsigned int. 4294967295 (0xffffffff)
LONG_MIN Minimum value for a variable of type long. –2147483648
LONG_MAX Maximum value for a variable of type long. 2147483647
ULONG_MAX Maximum value for a variable of type unsigned long. 4294967295 (0xffffffff)
_I64_MIN Minimum value for a variable of type __int64 -9223372036854775808
_I64_MAX Maximum value for a variable of type __int64 9223372036854775807
_UI64_MAX Maximum value for a variable of type unsigned __int64 18446744073709551615 (0xffffffffffffffff)

Limits on Floating-Point Constants

Constant Meaning Value
FLT_DIG DBL_DIG LDBL_DIG Number of digits, q, such that a floating-point number with q decimal digits can be rounded into a floating-point representation and back without loss of precision. 6 15 15
FLT_EPSILON DBL_EPSILON LDBL_EPSILON Smallest positive number x, such that x + 1.0 is not equal to 1.0. 1.192092896e–07F 2.2204460492503131e–016 2.2204460492503131e–016
FLT_GUARD 0
FLT_MANT_DIG DBL_MANT_DIG LDBL_MANT_DIG Number of digits in the radix specified by FLT_RADIX in the floating-point significand. The radix is 2; hence these values specify bits. 24 53 53
FLT_MAX DBL_MAX LDBL_MAX Maximum representable floating-point number. 3.402823466e+38F 1.7976931348623158e+308 1.7976931348623158e+308
FLT_MAX_10_EXP DBL_MAX_10_EXP LDBL_MAX_10_EXP Maximum integer such that 10 raised to that number is a representable floating-point number. 38 308 308
FLT_MAX_EXP DBL_MAX_EXP LDBL_MAX_EXP Maximum integer such that FLT_RADIX raised to that number is a representable floating- point number. 128 1024 1024
FLT_MIN DBL_MIN LDBL_MIN Minimum positive value. 1.175494351e–38F 2.2250738585072014e–308 2.2250738585072014e–308
FLT_MIN_10_EXP DBL_MIN_10_EXP LDBL_MIN_10_EXP Minimum negative integer such that 10 raised to that number is a representable floating- point number. –37

–307

–307

FLT_MIN_EXP DBL_MIN_EXP LDBL_MIN_EXP Minimum negative integer such that FLT_RADIX raised to that number is a representable floating-point number. –125

–1021

–1021

FLT_NORMALIZE 0
FLT_RADIX _DBL_RADIX _LDBL_RADIX Radix of exponent representation. 2 2 2
FLT_ROUNDS _DBL_ROUNDS _LDBL_ROUNDS Rounding mode for floating-point addition. 1 (near) 1 (near) 1 (near)

Data Type Ranges in C

Type Name Bytes Other Names Range of Values
int 4 signed -2,147,483,648 to 2,147,483,647
unsigned int 4 unsigned 0 to 4,294,967,295
__int8 1 char -128 to 127
unsigned __int8 1 unsigned char 0 to 255
__int16 2 short, short int, signed short int -32,768 to 32,767
unsigned __int16 2 unsigned short, unsigned short int 0 to 65,535
__int32 4 signed, signed int, int -2,147,483,648 to 2,147,483,647
unsigned __int32 4 unsigned, unsigned int 0 to 4,294,967,295
__int64 8 long long, signed long long -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
unsigned __int64 8 unsigned long long 0 to 18,446,744,073,709,551,615
bool 1 none false or true
char 1 none -128 to 127 by default

0 to 255 when compiled by using /J

signed char 1 none -128 to 127
unsigned char 1 none 0 to 255
short 2 short int, signed short int -32,768 to 32,767
unsigned short 2 unsigned short int 0 to 65,535
long 4 long int, signed long int -2,147,483,648 to 2,147,483,647
unsigned long 4 unsigned long int 0 to 4,294,967,295
long long 8 none (but equivalent to __int64) -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807
unsigned long long 8 none (but equivalent to unsigned __int64) 0 to 18,446,744,073,709,551,615
enum varies none
float 4 none 3.4E +/- 38 (7 digits)
double 8 none 1.7E +/- 308 (15 digits)
long double same as double none Same as double
wchar_t 2 __wchar_t 0 to 65,535

My .vimrc

" Basis
"set cul
set nowrap
set mouse=a
"set paste
set history=1000
set bg=dark
syntax on
set ai
set cin
set sw=2
set sts=2
set ts=2
set nu
set si
set sm
set nobk
"set guioptions-=T
"set guioptions-=m
set ignorecase smartcase
set vb t_vb=
set ruler
set magic
set nohls
set incsearch
set et
set sta
"set spell
"set ww=b,s,h,l,<,>,~,[,]
set encoding=utf-8
set fileencodings=ucs-bom,utf-8,cp936,gb18030,big5,euc-jp,euc-kr,latin1
set ambiwidth=double
set cino=:0g0t0(sus
set selection=inclusive
set keymodel=startsel,stopsel
"set wildmenu
"set cmdheight=1
"set laststatus=2
"set statusline=\ %<%F[%1<em>%M%</em>%n%R%H]%=\ %y\ %0(%{&fileformat}\ %{&encoding}\ %l/%L:%c%)
"set foldenable
"set foldmethod=syntax
"set foldcolumn=0
"setlocal foldlevel=1
"set foldclose=all
"nnoremap <space> @=((foldclosed(line('.')) < -3) ? 'zc' : 'zo')<cr>
colorscheme delek</cr></space>

" Plugins
set nocp
filetype off

" set the runtime path to include Vundle and initialize
set rtp+=~/.vim/bundle/Vundle.vim
call vundle#begin()
" alternatively, pass a path where Vundle should install plugins
"call vundle#begin('~/some/path/here')

" let Vundle manage Vundle, required
Plugin 'VundleVim/Vundle.vim'
Plugin 'sCRooloose/nerdtree'
Plugin 'Valloric/YouCompleteMe'
Plugin 'vim-syntastic/syntastic'
Plugin 'easymotion/vim-easymotion'
Plugin 'fholgado/minibufexpl.vim'
Plugin 'vim-airline/vim-airline'
Plugin 'vim-sCRipts/taglist.vim'
Plugin 'majutsushi/tagbar'
Plugin 'Yggdroot/indentLine'
Plugin 'Yggdroot/vim-mark'
Plugin 'kien/ctrlp.vim'
Plugin 'sCRooloose/nerdcommenter'
Plugin 'sjl/gundo.vim'
Plugin 'godlygeek/tabular'

" The following are examples of different formats supported.
" Keep Plugin commands between vundle#begin/end.
" plugin on GitHub repo
"Plugin 'tpope/vim-fugitive'
" plugin from http://vim-sCRipts.org/vim/sCRipts.html
"Plugin 'L9'
" Git plugin not hosted on GitHub
"Plugin 'git://git.wincent.com/command-t.git'
" git repos on your local machine (i.e. when working on your own plugin)
"Plugin 'file:///home/gmarik/path/to/plugin'
" The sparkup vim sCRipt is in a subdirectory of this repo called vim.
" Pass the path to set the runtimepath properly.
"Plugin 'rstaCRuz/sparkup', {'rtp': 'vim/'}
" Install L9 and avoid a Naming conflict if you've already installed a
" different version somewhere else.
"Plugin 'ascenator/L9', {'name': 'newL9'}

" All of your Plugins must be added before the following line
call vundle#end()            " required
filetype plugin indent on    " required
" To ignore plugin indent changes, instead use:
"filetype plugin on
"
" Brief help
" :PluginList       - lists configured plugins
" :PluginInstall    - installs plugins; append <code>!</code> to update or just :PluginUpdate
" :PluginSearch foo - searches for foo; append <code>!</code> to refresh local cache
" :PluginClean      - confirms removal of unused plugins; append <code>!</code> to auto-approve removal
"
" see :h vundle for more details or wiki for FAQ
" Put your non-Plugin stuff after this line

let mapleader=","

let g:ycm_global_ycm_extra_conf = '~/.ycm_extra_conf.py'
nnoremap <leader>gt :YcmCompleter GoToDefinitionElseDeclaration<cr></cr></leader>

let g:EasyMotion_smartcase = 1
nnoremap <leader><leader>h <plug>(easymotion-linebackward)
nnoremap <leader><leader>j <plug>(easymotion-j)
nnoremap <leader><leader>k <plug>(easymotion-k)
nnoremap <leader><leader>l <plug>(easymotion-lineforward)
nnoremap <leader><leader>. <plug>(easymotion-repeat)</plug></leader></leader></plug></leader></leader></plug></leader></leader></plug></leader></leader></plug></leader></leader>

let g:syntastic_enable_signs = 1
let g:syntastic_error_symbol = '!'
let g:syntastic_warning_symbol = '?'
let g:syntastic_check_on_open = 1
let g:syntastic_check_on_wq = 0
let g:syntastic_enable_highlighting = 1

nnoremap <leader>a= :Tabularize /=<cr>
vnoremap <leader>a= :Tabularize /=<cr>
nnoremap <leader>a: :Tabularize /:\zs<cr>
vnoremap <leader>a: :Tabularize /:\zs<cr></cr></leader></cr></leader></cr></leader></cr></leader>

nnoremap <f2> :NERDTreeToggle<cr>
nnoremap <f3> :TlistToggle<cr>
nnoremap <f4> :TagbarToggle<cr>
nnoremap <f5> :GundoToggle<cr>
nnoremap <f7> :w<cr>:!clang++ -std=c++11 % -o %< && time ./%<<cr>
nnoremap <f9> :MBEbp<cr>
nnoremap <f10> :MBEbn<cr></cr></f10></cr></f9></cr></cr></f7></cr></f5></cr></f4></cr></f3></cr></f2>

inoremap ; ;<esc>a
inoremap ' <c-r>=QuoteDelim("'")<cr><esc>a
inoremap " <c-r>=QuoteDelim('"')<cr><esc>a
inoremap ( ()<esc>i
inoremap ) <c-r>=ClosePair(')')<cr><esc>a
inoremap [ []<esc>i
inoremap ] <c-r>=ClosePair(']')<cr><esc>a
inoremap { {<cr>}<esc>O
"inoremap } <c-r>=CloseBracket()<cr></cr></c-r></esc></cr></esc></cr></c-r></esc></esc></cr></c-r></esc></esc></cr></c-r></esc></cr></c-r></esc>

function ClosePair(char)
if getline('.')[col('.') - 1] == a:char
return "\<right>"
else
return a:char
endif
endf</right>

function CloseBracket()
if match(getline(line('.') + 1), '\s*}') < 0
return "\<cr>}"
else
return "\<esc>j0f}a"
endif
endf</esc></cr>

function QuoteDelim(char)
let line = getline('.')
let col = col('.')
if line[col - 2] == "\"
return a:char
elseif line[col - 1] == a:char
return "\<right>"
else
return a:char.a:char."\<esc>i"
endif
endf