C語言讀取bmp位圖文件(含bmp格式定義)

loadbmp.h

#ifndef _LOADBMP_H_
#define _LOADBMP_H_
typedef unsigned char    BYTE;
typedef unsigned short    WORD;
typedef unsigned long    DWORD;

typedef struct {
    /* BITMAPFILEHEADER*/
    BYTE    bfType[2];
    DWORD    bfSize;
    WORD    bfReserved1;
    WORD    bfReserved2;
    DWORD    bfOffBits;
} BMPFILEHEAD;

#define FILEHEADSIZE 14

/* windows style*/
typedef struct {
    /* BITMAPINFOHEADER*/
    DWORD    BiSize;
    DWORD    BiWidth;
    DWORD    BiHeight;
    WORD    BiPlanes;
    WORD    BiBitCount;
    DWORD    BiCompression;
    DWORD    BiSizeImage;
    DWORD    BiXpelsPerMeter;
    DWORD    BiYpelsPerMeter;
    DWORD    BiClrUsed;
    DWORD    BiClrImportant;
} BMPINFOHEAD;

#define INFOHEADSIZE 40

typedef struct _BMP {
    BMPINFOHEAD info;
    unsigned char *rgba;
    unsigned char *yuy2;
    unsigned char *yv12;
} BMP, *PBMP;

int LoadBMP(char *name, PBMP pbmp);
int ReleaseBMP(PBMP pbmp);
void rgb_to_yuv(unsigned int r, unsigned int g, unsigned int b,
    unsigned int *y, unsigned int *u, unsigned int *v);
#endif/*_LOADBMP_H_*/

loadbmp.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>

#include "loadbmp.h"

void rgb_to_yuv(unsigned int r, unsigned int g, unsigned int b,
    unsigned int *y, unsigned int *u, unsigned int *v)
{
    double dy, du, dv;

    dy = (0.257 * (double)r) +
        (0.504 * (double)g) + (0.098 * (double)b) + 16.0;
    dv= (0.439 * (double)r) - (0.368 * (double)g) - (0.071 * (double)b) +
        128.0;
    du = -(0.148 * (double)r) - (0.291 * (double)g) +
        (0.439 * (double)b) + 128.0;

    *y = (unsigned int)dy & 0xff;
    *v = (unsigned int)dv & 0xff;
    *u = (unsigned int)du & 0xff;
}

static void
convert_to_yv12(PBMP pbmp)
{
    int x, y;
    unsigned char *in_ptr, *out_ptr_y, *out_ptr_u, *out_ptr_v;
    unsigned int Y, U, V;

    in_ptr = pbmp->rgba;
    out_ptr_y = pbmp->yv12;
    out_ptr_u = out_ptr_y + pbmp->info.BiWidth * pbmp->info.BiHeight;
    out_ptr_v = out_ptr_u + pbmp->info.BiWidth * pbmp->info.BiHeight / 4;
    for (y = 0; y < pbmp->info.BiHeight; y++) {
        for (x = 0; x < pbmp->info.BiWidth; x++) {
            rgb_to_yuv(in_ptr[0], in_ptr[1], in_ptr[2], &Y, &U, &V);
            in_ptr += pbmp->info.BiBitCount / 8;
            *out_ptr_y++ = Y;
            if (x % 2 == 0 && y % 2 == 0) {
                *out_ptr_u++ = V;
                *out_ptr_v++ = U;
            }
        }
    }
}

static void
convert_to_yuy2(PBMP pbmp)
{
    int x, y;
    unsigned char *in, *out;
    unsigned int Y, U, V;

    in = pbmp->rgba;
    out = pbmp->yuy2;
    for (y = 0; y < pbmp->info.BiHeight; y++) {
        for (x = 0; x < pbmp->info.BiWidth; x++) {
            static int cnt = 0;
            rgb_to_yuv(in[0], in[1], in[2], &Y, &U, &V);
            in += pbmp->info.BiBitCount / 8;
            *(out) = Y;
            if (cnt %2 == 0)
                *(out+1) = V;
            else
                *(out+1) = U;
            out+= 2;
            cnt++;
        }
    }
}

int LoadBMP(char *name, PBMP pbmp)
{
    int        fd;
    int        headsize;
    BMPFILEHEAD    bmpf;
    unsigned char     headbuffer[INFOHEADSIZE];

    fd = open(name, O_RDONLY);
    if (fd < 0) {
        perror("open");
        return -1;
    }

    read(fd, &headbuffer, FILEHEADSIZE);
    bmpf.bfType[0] = headbuffer[0];
    bmpf.bfType[1] = headbuffer[1];
    if (*(WORD*)&bmpf.bfType[0] != 0x4D42) /* 'BM' */
        return -2;    /* not bmp image*/

    bmpf.bfOffBits = *((DWORD*)&headbuffer[10]);

    if (read(fd,&headsize,sizeof(DWORD)) != sizeof(DWORD))
        return 0;    /* not bmp image*/

    read(fd, &headbuffer, INFOHEADSIZE - sizeof(DWORD));
    pbmp->info.BiWidth = *(DWORD*)(&headbuffer[0]);
    pbmp->info.BiHeight = *(DWORD*)(&headbuffer[4]);
    pbmp->info.BiBitCount = *(DWORD*)(&headbuffer[10]);
    pbmp->info.BiSizeImage = *(DWORD*)(&headbuffer[16]);

    pbmp->rgba = (unsigned char *)malloc(pbmp->info.BiSizeImage);
    if (!pbmp->rgba) {
        perror("malloc");
        exit(EXIT_FAILURE);
    }
//    pbmp->yuy2 = (unsigned char *)malloc(pbmp->info.BiWidth * pbmp->info.BiHeight * 2);
//    if (!pbmp->yuy2) {
//        perror("malloc");
//        exit(EXIT_FAILURE);
//    }
//    pbmp->yv12 = (unsigned char *)malloc(pbmp->info.BiWidth * pbmp->info.BiHeight * 3 / 2);
//    if (!pbmp->yv12) {
//        perror("malloc");
//        exit(EXIT_FAILURE);
//    }

    lseek(fd, bmpf.bfOffBits, SEEK_SET);
    if (read(fd, pbmp->rgba, pbmp->info.BiSizeImage) != pbmp->info.BiSizeImage) {
        perror("read");
        return -4;
    }

//    convert_to_yv12(pbmp);
//    convert_to_yuy2(pbmp);
    printf("LoadBMP: %s %ldx%ldx%d\n", name, pbmp->info.BiWidth, pbmp->info.BiHeight, pbmp->info.BiBitCount);
    close(fd);

    return 0;
}

int ReleaseBMP(PBMP pbmp)
{
    if (pbmp->rgba) {
        free(pbmp->rgba);
        pbmp->rgba = NULL;
    }
//    if (pbmp->yuy2) {
//        free(pbmp->yuy2);
//        pbmp->yuy2 = NULL;
//    }
//    if (pbmp->yv12) {
//        free(pbmp->yv12);
//        pbmp->yv12 = NULL;
//    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章