BMP影象的讀取和生成
阿新 • • 發佈:2019-01-01
1. BMP.h
#ifndef _BMP_H_
#define _BMP_H_
#ifdef __cplusplus
extern "C" {
#endif
typedef enum _BIT_DATA_TYPE_{
BIT32 = 1, //讀取或儲存成32位
BIT24 = 2, //讀取或儲存成24位
}BITDATATYPE;
typedef struct _BMPFILEHEAD_{
unsigned char type[2 ]; //儲存 'B' 'M' 2位元組
unsigned int size; //點陣圖檔案大小 4位元組
unsigned short reserved1; //保留字 2位元組
unsigned short reserved2; //保留字 2位元組
unsigned int offBits; //點陣圖資料起始位置 4位元組
}BMPHEAD;
typedef struct _BMPFILEINFOHEAD_{
unsigned int selfSize; //點陣圖資訊頭的大小 4位元組
long bitWidth; //點陣圖的寬度,以畫素為單位 4位元組
long bitHeight; //點陣圖的高度,以畫素為單位 4位元組
unsigned short bitPlanes; //目標裝置的級別,必須為1 2位元組
unsigned short pixelBitCount; //每個畫素所需的位數 2位元組
unsigned int compression; //點陣圖壓縮型別,0(不壓縮) 4位元組
unsigned int sizeImage; //點陣圖的大小,以位元組為單位 4位元組
long pixelXPerMeter; //點陣圖的水平解析度,每米畫素數 4位元組
long pixelYPerMeter; //點陣圖的垂直解析度,每米畫素數 4位元組
unsigned int colorUsed; //點陣圖實際使用的顏色表中的顏色數 4位元組
unsigned int colorImportant; //點陣圖顯示過程中重要的顏色數 4位元組
}BMPINFOHEAD;
typedef struct _IMAGE_{
int width;
int height;
int channels;
unsigned char * data;
}IMAGE;
int LoadBMP(const char * file, IMAGE* out_img, BITDATATYPE bit_data_type);
int WriteBMP(const char * file, IMAGE * in_img, BITDATATYPE bit_data_type);
int freeImage(IMAGE * img);
#ifdef __cplusplus
}
#endif
#endif
2. LoadBMP.c
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include "BMP.h"
#define BMP_SIZE_FILEHEADER 14
#define BMP_SIZE_INFOHEADER 40
#define BMP_COLOR_BITS_24 24
#define BMP_COLOR_BITS_32 32
static unsigned int uInt16Number(unsigned char buf[2]){
return (buf[1] << 8) | buf[0];
}
static unsigned int uInt32Number(unsigned char buf[4]){
unsigned numb = buf[3];
numb = (numb << 8) | buf[2];
numb = (numb << 8) | buf[1];
numb = (numb << 8) | buf[0];
return numb;
}
static void IntTo2Bytes(int val, unsigned char buf[2]){
buf[0] = (unsigned char)val;
buf[1] = (unsigned char)(val >> 8);
}
static void IntTo4Bytes(int val, unsigned char buf[4]){
buf[0] = (unsigned char)val;
buf[1] = (unsigned char)(val >> 8);
buf[2] = (unsigned char)(val >> 16);
buf[3] = (unsigned char)(val >> 24);
}
static int ReadFileHeader(FILE* f, int* bitmap_pos){
unsigned char header[BMP_SIZE_FILEHEADER];
BMPHEAD bmp_head;
int numb = 0;
int offset = 0;
if (fseek(f, 0, SEEK_SET))
return -1;
//讀取bmp head資訊
numb = fread(header, BMP_SIZE_FILEHEADER, 1, f);
if (numb != 1)
return -2;
// 0 - 1
if (header[0] != 'B' || header[1] != 'M')
return -3;
bmp_head.type[0] = header[0];
bmp_head.type[1] = header[1];
// 2 - 5
bmp_head.size = uInt32Number(header + 2);
// 6 - 7
// 8 - 9
// 10 - 13
offset = uInt32Number(header + 10);
if(offset != 54)
return -4;
*bitmap_pos = offset;
return 0;
}
static int ReadFileInfoHead(FILE* f, IMAGE * img){
unsigned char header[BMP_SIZE_INFOHEADER];
BMPINFOHEAD bmp_info_head;
int numb = 0;
if (fseek(f, BMP_SIZE_FILEHEADER, SEEK_SET))
return -1;
//讀取bmp info head資訊
numb = fread(header, BMP_SIZE_INFOHEADER, 1, f);
if (numb != 1)
return -2;
// 14 - 17
bmp_info_head.selfSize = uInt32Number(header);
if(bmp_info_head.selfSize != 40)
return -3;
// 18 - 21
bmp_info_head.bitWidth = (long)uInt32Number(header + 4);
// 22 - 25
bmp_info_head.bitHeight = (long)uInt32Number(header + 8);
// 26 - 27
bmp_info_head.bitPlanes = (unsigned short)uInt16Number(header + 12);
// 28 - 29
bmp_info_head.pixelBitCount = (unsigned short)uInt16Number(header + 14);
// 30 - 33
bmp_info_head.compression = uInt32Number(header + 16);
// 34 - 37
bmp_info_head.sizeImage = uInt32Number(header + 20);
// 38 - 41
bmp_info_head.pixelXPerMeter = (long)uInt32Number(header + 24);
// 42 - 45
bmp_info_head.pixelYPerMeter = (long)uInt32Number(header + 28);
// 46 - 49
bmp_info_head.colorUsed = uInt32Number(header + 32);
// 50 - 53
bmp_info_head.colorImportant = uInt32Number(header + 36);
img->width = bmp_info_head.bitWidth;
img->height = bmp_info_head.bitHeight;
return (int)(bmp_info_head.pixelBitCount);
}
int LoadBMP(const char* file, IMAGE* out_img, BITDATATYPE bit_data_type){
FILE* f;
int bitmap_pos;
int n_bits;
int flErr = 0;
fopen_s(&f, file, "rb");
if (!f)
return -11;
if (out_img == NULL)
return -12;
if (0 > (flErr = ReadFileHeader(f, &bitmap_pos))){
fclose(f);
return flErr;
}
n_bits = ReadFileInfoHead(f, out_img);
if(n_bits == BMP_COLOR_BITS_24){
int rgb_size;
int rgba_size;
unsigned char* rgb;
int y;
unsigned char* line;
int rest_4;
if (fseek(f, bitmap_pos, SEEK_SET)){
fclose(f);
return -16;
}
rgb_size = 3 * out_img->width;
rgba_size = 4 * out_img->width;
rest_4 = rgb_size % 4;
if (rest_4 > 0)
rgb_size += 4 - rest_4;
if(bit_data_type == 1)
{
out_img->channels = 4;
out_img->data = (unsigned char*)malloc(out_img->width * out_img->height * 4);
if (out_img->data == NULL)
return -17;
rgb = (unsigned char*)malloc(rgb_size);
if(NULL == rgb)
return -18;
for(y = out_img->height - 1; y >= 0; y --){
int numb = 0;
int x = 0;
numb = fread(rgb, rgb_size, 1, f);
if (numb != 1){
fclose(f);
free(rgb);
return -19;
}
numb = 0;
line = out_img->data + out_img->width * 4 * y;
for (x = 0; x < out_img->width ; x++){
line[3] = 255;
line[2] = rgb[numb++];
line[1] = rgb[numb++];
line[0]= rgb[numb++];
line += 4;
}
}
}else if(bit_data_type == 2)
{
out_img->channels = 3;
out_img->data = (unsigned char*)malloc(out_img->width * out_img->height * 3);
if (out_img->data == NULL)
return -17;
rgb = (unsigned char*)malloc(rgb_size);
if(NULL == rgb)
return -18;
for(y = out_img->height - 1; y >= 0; y --){
int numb = 0;
int x = 0;
numb = fread(rgb, rgb_size, 1, f);
if (numb != 1){
fclose(f);
free(rgb);
return -19;
}
numb = 0;
line = out_img->data + out_img->width * 3 * y;
for (x = 0; x < out_img->width ; x++){
line[2] = rgb[numb++];
line[1] = rgb[numb++];
line[0]= rgb[numb++];
line += 3;
}
}
}
fclose(f);
free(rgb);
}else if(n_bits == BMP_COLOR_BITS_32)
{
int rgba_size;
unsigned char* rgba;
int y;
unsigned char* line;
if (fseek(f, bitmap_pos, SEEK_SET)){
fclose(f);
return -16;
}
rgba_size = 4 * out_img->width;
if(bit_data_type == 1)
{
out_img->channels = 4;
out_img->data = (unsigned char*)malloc(out_img->width * out_img->height * 4);
if (out_img->data == NULL)
return -17;
rgba = (unsigned char*)malloc(rgba_size);
if(NULL == rgba)
return -18;
for (y = out_img->height - 1; y >= 0; y --){
int numb = 0;
int x = 0;
numb = fread(rgba, rgba_size, 1, f);
if (numb != 1){
fclose(f);
free(rgba);
return -19;
}
numb = 0;
line = out_img->data + out_img->width * 4 * y;
for (x = 0; x < out_img->width ; x++){
line[2] = rgba[numb++];//B
line[1] = rgba[numb++];//G
line[0] = rgba[numb++];//R
line[3]= rgba[numb++];//A
line += 4;
}
}
}else if(bit_data_type == 2)
{
out_img->channels = 3;
out_img->data = (unsigned char*)malloc(out_img->width * out_img->height * 3);
if (out_img->data == NULL)
return -17;
rgba = (unsigned char*)malloc(rgba_size);
if(NULL == rgba)
return -18;
for (y = out_img->height - 1; y >= 0; y --){
int numb = 0;
int x = 0;
numb = fread(rgba, rgba_size, 1, f);
if (numb != 1){
fclose(f);
free(rgba);
return -19;
}
numb = 0;
line = out_img->data + out_img->width * 3 * y;
for (x = 0; x < out_img->width ; x++){
line[2] = rgba[numb++];//B
line[1] = rgba[numb++];//G
line[0] = rgba[numb++];//R
line += 3;
numb ++;
}
}
}
fclose(f);
free(rgba);
}
else{
return -20;
}
return 0;
}
static int WriteFileHeader(FILE* f, IMAGE * in_img, BITDATATYPE bit_data_type)
{
unsigned char header[BMP_SIZE_FILEHEADER];
int imgWidth, imgHeight;
int imageSize;
int numb = 0;
int offset = 0;
if (fseek(f, 0, SEEK_SET))
return -1;
header[0] = 'B';
header[1] = 'M';
imgWidth = in_img->width;
imgHeight = in_img->height;
if(bit_data_type == 1)
{
imageSize = imgWidth * 4 * imgHeight + BMP_SIZE_FILEHEADER + BMP_SIZE_INFOHEADER;
}else if(bit_data_type == 2)
{
int rgbSize;
int rest_4;
rgbSize = imgWidth * 3;
rest_4 = rgbSize % 4;
if (rest_4 > 0)
rgbSize += 4 - rest_4;
imageSize = rgbSize * imgHeight + BMP_SIZE_FILEHEADER + BMP_SIZE_INFOHEADER;
}
IntTo4Bytes(imageSize, header + 2);
IntTo4Bytes(0, header + 6);
IntTo4Bytes((BMP_SIZE_FILEHEADER + BMP_SIZE_INFOHEADER), header + 10);
//讀取bmp head資訊
numb = fwrite(header, BMP_SIZE_FILEHEADER, 1, f);
if (numb != 1)
return -2;
return 0;
}
static int WriteFileInfoHead(FILE* f, IMAGE * in_img, BITDATATYPE bit_data_type){
unsigned char header[BMP_SIZE_INFOHEADER];
int imageSize = 0;
int numb = 0;
if (fseek(f, BMP_SIZE_FILEHEADER, SEEK_SET))
return -1;
// 14- 17
IntTo4Bytes(BMP_SIZE_INFOHEADER, header);
// 18 - 21
IntTo4Bytes(in_img->width, header + 4);
// 22 - 25
IntTo4Bytes(in_img->height, header + 8);
// 26 - 27
IntTo2Bytes(1, header + 12);
// 28 - 29
if(bit_data_type == 1)
{
IntTo2Bytes(32, header + 14);
}else if(bit_data_type == 2)
{
IntTo2Bytes(24, header + 14);
}
// 30 - 33
IntTo4Bytes(0, header + 16);
// 34 - 37
if(bit_data_type == 1)
{
imageSize = in_img->width * 4 * in_img->height;
}else if(bit_data_type == 2)
{
int rgbSize;
int rest_4;
rgbSize = in_img->width * 3;
rest_4 = rgbSize % 4;
if (rest_4 > 0)
rgbSize += 4 - rest_4;
imageSize = rgbSize * in_img->height;
}
IntTo4Bytes(imageSize, header + 20);
// 38 - 41
IntTo4Bytes(0, header + 24);
// 42 - 45
IntTo4Bytes(0, header + 28);
// 46 - 49
IntTo4Bytes(0, header + 32);
// 50 - 53
IntTo4Bytes(0, header + 36);
numb = fwrite(header, BMP_SIZE_INFOHEADER, 1, f);
if (numb != 1)
return -2;
return 0;
}
int WriteBMP(const char * file, IMAGE * in_img, BITDATATYPE bit_data_type){
FILE* f;
int flErr = 0;
fopen_s(&f, file, "wb");
if (!f)
return -1;
if (in_img == NULL)
return -2;
if (0 != WriteFileHeader(f, in_img, bit_data_type)){
fclose(f);
return -3;
}
if(0 != WriteFileInfoHead(f, in_img, bit_data_type)){
fclose(f);
return -4;
}
if(bit_data_type == 2){
int rgb_size;
unsigned char * rgb;
int y;
unsigned char* line;
int rest_4;
rgb_size = 3 * in_img->width;
rest_4 = rgb_size % 4;
if (rest_4 > 0)
rgb_size += 4 - rest_4;
rgb = (unsigned char *)malloc(rgb_size * in_img->height);
if (rgb == NULL)
return -6;
if(in_img->channels == 4)
{
for (y = 0; y < in_img->height; y ++){
int numb = 0;
int x = 0;
numb = in_img->width * 4 * y;
line = rgb + rgb_size * (in_img->height - y - 1);
for (x = 0; x < in_img->width; x++){
line[2] = in_img->data[numb++];
line[1] = in_img->data[numb++];
line[0]= in_img->data[numb++];
line += 3;
numb ++;
}
}
}else if(in_img->channels == 3)
{
for (y = 0; y < in_img->height; y ++){
int numb = 0;
int x = 0;
numb = in_img->width * 3 * y;
line = rgb + rgb_size * (in_img->height - y - 1);
for (x = 0; x < in_img->width; x++){
line[2] = in_img->data[numb++];
line[1] = in_img->data[numb++];
line[0]= in_img->data[numb++];
line += 3;
}
}
}
if (fseek(f, (BMP_SIZE_FILEHEADER + BMP_SIZE_INFOHEADER), SEEK_SET)){
fclose(f);
return -5;
}
fwrite(rgb, rgb_size * in_img->height, 1, f);
fclose(f);
free(rgb);
}else if(bit_data_type == 1)
{
int rgba_size;
unsigned char * rgba;
int y;
unsigned char* line;
rgba_size = 4 * in_img->width;
rgba = (unsigned char *)malloc(rgba_size * in_img->height);
if (rgba == NULL)
return -6;
if(in_img->channels == 4)
{
for (y = 0; y < in_img->height; y ++){
int numb = 0;
int x = 0;
numb = in_img->width * 4 * y;
line = rgba + rgba_size * (in_img->height - y - 1);
for (x = 0; x < in_img->width; x++){
line[2] = in_img->data[numb++];//R
line[1] = in_img->data[numb++];//G
line[0]= in_img->data[numb++];//B
line[3]= in_img->data[numb++];//A
line += 4;
}
}
}else if(in_img->channels == 3)
{
for (y = 0; y < in_img->height; y ++){
int numb = 0;
int x = 0;
numb = in_img->width * 3 * y;
line = rgba + rgba_size * (in_img->height - y - 1);
for (x = 0; x < in_img->width; x++){
line[2] = in_img->data[numb++];
line[1] = in_img->data[numb++];
line[0]= in_img->data[numb++];
line[3]= 255;
line += 4;
}
}
}
if (fseek(f, (BMP_SIZE_FILEHEADER + BMP_SIZE_INFOHEADER), SEEK_SET)){
fclose(f);
return -5;
}
fwrite(rgba, rgba_size * in_img->height, 1, f);
fclose(f);
free(rgba);
}
else{
return -20;
}
return 0;
}
int freeImage(IMAGE * img){
if(img == NULL)
{
return -1;
}
if(img->data != NULL)
{
free(img->data);
img->data = NULL;
img->width = 0;
img->height = 0;
}
return 0;
}
3. main.cpp 測試函式
#include <stdio.h>
#include <stdlib.h>
#include "BMP.h"
int main(void)
{
IMAGE img;
LoadBMP("test002.bmp", &img, BIT24);
WriteBMP("test003.bmp", &img, BIT24);
freeImage(&img);
system("pause");
return 0;
}
如有疑問可留言