-
Notifications
You must be signed in to change notification settings - Fork 0
Lesson2
Junjie edited this page Aug 12, 2024
·
7 revisions
First we need to parse the BMP format, see BMP for format information.
首先我们需要解析BMP文件格式,细节参看BMP
Header 14 bytes
文件头 14 字节
#pragma pack(push, 2)
struct bmp_file_header {
uint16_t magic; // "BM"
uint32_t size;
uint32_t reserved;
uint32_t offset;
};
#pragma pack(pop)
InfoHeader 40 bytes
信息头40字节
struct bmp_info_header {
uint32_t size; // Size of this header (in bytes)
int32_t width; // width of bitmap in pixels
int32_t height; // width of bitmap in pixels
// (if positive, bottom-up, with origin in lower left corner)
// (if negative, top-down, with origin in upper left corner)
uint16_t planes; // No. of planes for the target device, this is always 1
uint16_t bit_count; // No. of bits per pixel
uint32_t compression; // 0 or 3 - uncompressed.
uint32_t size_image;
int32_t x_pixels_per_meter;
int32_t y_pixels_per_meter;
uint32_t colors_used;
uint32_t colors_important;
};
Well, for now it is good enough to parse the data from sample.bmp
现在的信息足够我们去解析sample.bmp中的数据了。
FILE *f = fopen(filename, "rb");
fread(&b->file_header, sizeof(struct bmp_file_header ), 1, f);
fread(&b->dib, sizeof(struct bmp_info_header), 1, f);
for (int i = upper; i >= bottom; i += delta) {
for(int j = 0; j < p->width; j ++) {
uint8_t px = fgetc(f);
//when the image have color palette, lookup the color table.
struct bmp_color_entry *clr = b->palette + px;
b->data[p->pitch * i + j * p->depth / 8] = clr->blue;
b->data[p->pitch * i + j * p->depth / 8 + 1] = clr->green;
b->data[p->pitch * i + j * p->depth / 8 + 2] = clr->red;
if (p->depth == 32) {
b->data[p->pitch * i + j * p->depth / 8 + 3] = clr->alpha;
}
}
}
That's it, we now have the pixels in the data array. Now we can feed the pixels to some module to display. In case we have different bmp files with different depth or compression, the code should be modified accordingly.
好了,现在像素数据都被我们保存在了data的数组里。现在可以将像素数据喂给显示模块了。 如果我们有不同的深度或者压缩方式的bmp文件,上面的代码也需要做相应的修改。
SDL2 is what we can use to easily draw picture.
我们可以是SDL2来简单画图显示这个图片。
A fully simple sample to render bmp picture is below.
完整绘制bmp图片的例子如下:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <SDL.h>
#include <stdint.h>
#pragma pack(push, 2)
struct bmp_file_header {
uint16_t signature;
uint32_t filesize;
uint32_t rsd;
uint32_t offset;
};
struct bmp_info_header {
uint32_t size;
uint32_t width;
uint32_t height;
uint16_t planes;
uint16_t bitsperpixels;
uint32_t compression;
uint32_t image_size;
uint32_t resolution_x;
uint32_t resolution_y;
uint32_t color_used;
uint32_t color_important;
};
#pragma pack(pop)
uint8_t* load_bmp(FILE *fp)
{
struct bmp_file_header fh;
int len = fread(&fh, sizeof(fh), 1, fp);
if (len < 1) {
return NULL;
}
printf("%C%C\n", fh.signature&0xFF, fh.signature>>8);
printf("file size %d\n", fh.filesize);
struct bmp_info_header info;
fread(&info, sizeof(info), 1, fp);
printf("width %d, height %d, depth %d\n",info.width, info.height, info.bitsperpixels);
printf("color used %d\n", info.color_used);
printf("image size %d\n", info.image_size);
fseek(fp, fh.offset, SEEK_SET);
int up;
int pitch = (((info.width * 3 + 3) >> 2) << 2); // agligned by four bytes
uint8_t *data = malloc(info.height * pitch);
for (int y = 0; y < info.height; y++) {
fread(data + (info.height-y)*pitch, pitch, 1, fp);
}
return data;
}
void display_bmp(uint8_t *data, int width, int height)
{
int ret = SDL_Init(SDL_INIT_EVERYTHING);
if (ret == -1) {
return;
}
SDL_Window *w = SDL_CreateWindow("show", SDL_WINDOWPOS_UNDEFINED,
SDL_WINDOWPOS_UNDEFINED, 640, 480,
SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE);
SDL_Renderer *r = SDL_CreateRenderer(
w, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
// SDL_Texture *t =SDL_CreateTexture(r, SDL_PIXELFORMAT_YV12, SDL_TEXTUREACCESS_STATIC,
// width, height);
// SDL_SetRenderTarget(r, t);
SDL_SetRenderDrawBlendMode(r, SDL_BLENDMODE_BLEND);
SDL_RenderClear(r);
int pitch = (((width * 3 + 3) >> 2)<< 2); //agligned by four bytes
SDL_Surface *s = SDL_CreateRGBSurfaceWithFormatFrom(data, width, height, 24, pitch,
SDL_PIXELFORMAT_BGR24);
SDL_Texture *t = SDL_CreateTextureFromSurface(r, s);
SDL_SetRenderTarget(r, t);
SDL_RenderCopy(r, t, NULL, NULL);
SDL_RenderPresent(r);
bool quit = false;
while (!quit) {
SDL_Event e;
while(SDL_PollEvent(&e)) {
if (e.type == SDL_KEYDOWN) {
quit = true;
break;
}
};
}
}
int
main(int argc, const char *argv[])
{
FILE *f = fopen(argv[1], "rb");
uint8_t *data = load_bmp(f);
fclose(f);
display_bmp(data, 640, 426);
free(data);
return 0;
}
- Claim no rights on posts. CC @junka
- Have fun with low level details.
- Fill an issue if you like.