예제 #1
0
static int read_bmp_header(const unsigned char *p)
{
    if (*p++ != 'B')
	return 0;
    if (*p++ != 'M')
	return 0;

    if (get_4(&p) != HEADER_SIZE + png.width * png.height * 4)
	return 0;

    get_4(&p);

    if (get_4(&p) != HEADER_SIZE)
	return 0;

    if (get_4(&p) != 40)
	return 0;

    if (get_4(&p) != png.width)
	return 0;
    if (get_4(&p) != -png.height)
	return 0;

    get_2(&p);
    if (get_2(&p) != 32)
	return 0;

    if (get_4(&p) != 0)
	return 0;
    if (get_4(&p) != png.width * png.height * 4)
	return 0;

    get_4(&p);
    get_4(&p);
    get_4(&p);
    get_4(&p);

    return 1;
}
예제 #2
0
void ImageBMP::ReadBMP(const uint8_t* data, unsigned len, bool transparent,
					   int& width, int& height, void*& pixels) {
	pixels = NULL;

	// BITMAPFILEHEADER structure
	//
	// 0	2	signature: 'B','M'
	// 2	4	file size
	// 6	2	reserved
	// 8	2	reserved
	// 10	4	offset to bitmap data
	static const unsigned BITMAPFILEHEADER_SIZE = 14;

	if (len < 64) {
		Output::Error("Not a valid BMP file.");
		return;
	}

	// file size is skipped because every program writes other data into
	// this field and not needed for correct decoding.

	const unsigned bits_offset = get_4(&data[10]);

	// BITMAPINFOHEADER structure (BMP 2.x and 3.x)
	//
	// 0	4	BITMAPINFOHEADER size
	// 4	4	width
	// 8	4	height (+ve => bottom-up, -ve => top-down)
	// 12	2	number of planes (must be 1)
	// 14	2	bits per pixel
	// 16	4	compression
	// 20	4	image size
	// 24	4	X pixels per meter
	// 28	4	Y pixels per meter
	// 32	4	number of palette colors used
	// 36	4	number of important palette colors
	// size ... palette (starts at 40 in BMP 2.x/3.x and 108 in BMP 4.x)


	width = (int) get_4(&data[BITMAPFILEHEADER_SIZE + 4]);
	height = (int) get_4(&data[BITMAPFILEHEADER_SIZE + 8]);

	// bitmap scan lines need to be aligned to 32 bit boundaries, add padding if needed
	int padding = (width % 4 != 0) ? 4 - width % 4 : 0;

	bool vflip = height > 0;
	if (!vflip)
		height = -height;

	const int planes = (int) get_2(&data[BITMAPFILEHEADER_SIZE + 12]);
	if (planes != 1) {
		Output::Error("BMP planes is not 1.");
		return;
	}

	const int depth = (int) get_2(&data[BITMAPFILEHEADER_SIZE + 14]);
	if (depth != 8) {
		Output::Error("BMP image is not 8-bit.");
		return;
	}

	const int compression = get_4(&data[BITMAPFILEHEADER_SIZE + 16]);
	static const int BI_RGB = 0;
	if (compression != BI_RGB) {
		Output::Error("BMP image is compressed.");
		return;
	}

	int num_colors = std::min(256U, get_4(&data[BITMAPFILEHEADER_SIZE + 32]));
	uint8_t (*palette)[4] = (uint8_t(*)[4]) &data[BITMAPFILEHEADER_SIZE +
		get_4(&data[BITMAPFILEHEADER_SIZE + 0])];
	const uint8_t* src_pixels = &data[bits_offset];

	// Ensure no palette entry is an exact duplicate of #0
	for (int i = 1; i < num_colors; i++) {
		if (palette[i][0] == palette[0][0] &&
			palette[i][1] == palette[0][1] &&
			palette[i][2] == palette[0][2]) {
			palette[i][0] ^= 1;
		}
	}

	pixels = malloc(width * height * 4);

	uint8_t* dst = (uint8_t*) pixels;
	for (int y = 0; y < height; y++) {
		const uint8_t* src = src_pixels + (vflip ? height - 1 - y : y) * (width + padding);
		for (int x = 0; x < width; x++) {
			const uint8_t& pix = *src++;
			const uint8_t* color = palette[pix];
			*dst++ = color[2];
			*dst++ = color[1];
			*dst++ = color[0];
			*dst++ = (transparent && pix == 0) ? 0 : 255;
		}
	}
}