BadApple 놀이는 원래 잡아하도록하지만 비트 맵 파일과 픽셀 정보를 저장하는 2 차원 배열을 읽기 위해 C 언어를 사용하는 방법에 대한 연구에 단순히 읽는 텍스트 파일 및 출력 내용, 그리고 마지막으로 설정되지 않았습니다.
첫 번째 단계는 자연 BMP 파일 형식을 파악하는 것입니다. 다양한 비트 맵 형식의 데이터 블록들은 압축되지 않기 때문에, 각 화소를 표현하는 비트의 몇몇 독립된 그룹으로 구성하거나, 읽기 및 쓰기가 비교적 간단되는 BMP 만 FREAD에서 요구하는 형식에 따라 이진 파일을 판독 할 필요 라인에.
네 부분에 대한 BMP 파일의 첫 부분은 BMP 파일 형식에 대한 정보가 저장된 데이터 파일의 형식은, 14 바이트의 총 점유하며이다. 두 번째 부분은 화상 데이터 정보가 비트 맵 이미지에 관한 저장된 정보, 40 바이트의 총 세 번째 부분은 옵션 팔레트, 마지막 화소 정보 영역이다.
아래의 표에서 각 필드의 의미 부 특정 :
설명 위의 형식에 따라, 우리는 그들을 설명하기 위해 몇 가지 구조를 정의 :
#pragma once
#include<stdio.h>
typedef unsigned int DWORD; // 4bytes
typedef unsigned short WORD; // 2bytes
typedef signed long LONG; // 4bytes
typedef unsigned char BYTE; // 1bytes
#pragma pack(push)
#pragma pack(1)// 修改默认对齐值
/*位图文件文件头结构体*/
typedef struct tagBITMAPFILEHEADER {
WORD bFileType;
DWORD bFileSize;
WORD bReserved1;
WORD bReserved2;
DWORD bPixelDataOffset;
}BITMAPFILEHEADER; //14bytes
#pragma pack(pop)
/*位图文件信息头结构体*/
typedef struct tagBITMAPINFOHEADER {
DWORD bHeaderSize; // 图像信息头总大小(40bytes)
LONG bImageWidth; // 图像宽度(像素)
LONG bImageHeight; // 图像高度
WORD bPlanes; // 应该是0
WORD bBitsPerPixel; // 像素位数
DWORD bCompression; // 图像压缩方法
DWORD bImageSize; // 图像大小(字节)
LONG bXpixelsPerMeter; // 横向每米像素数
LONG bYpixelsPerMeter; // 纵向每米像素数
DWORD bTotalColors; // 使用的颜色总数,如果像素位数大于8,则该字段没有意义
DWORD bImportantColors; // 重要颜色数,一般没什么用
}BITMAPINFOHEADER; //40bytes
/*位图文件调色板结构体*/
typedef struct tagRGBQUAD {
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
}RGBQUAD;
/*像素点RGB结构体*/
typedef struct tagRGB {
BYTE blue;
BYTE green;
BYTE red;
}RGBDATA;
의 #pragma (푸시) 팩
팩 모두 #pragma. (1) 파일 헤더의 사이즈를 지정하지 않은 경우, 구조의 자동 정렬을 취소하는 것이 바로 신체의기구의 크기를 출력 할 수 있다면, 14 바이트를 점유 할 수있는 구조 아니다 를 sizeof (BITMAPFILEHEADER ) 얻을 수 있습니다.
사실이 기관 기관 wingdi.h 당신이 GDI 구조를 직접 정의 사용할 수있는 윈도우를 사용하는 경우 문서는 정의.
이러한 잘 정의 된 구조는 비트 맵을 읽어 함수를 작성 후, 기본 접근 방식은 FREAD 크기에 의해 지정된 파일 같은 읽기 내용은 다음 문 머리로 요소의 지정된 수에서 읽을 수 있습니다 :
FREAD (infoHead,는 sizeof (BITMAPINFOHEADER), 1, FP)
스트림 파일 FP, infoHead 메모리 영역과 장소 포인터 포인트 infoHead BITMAPINFOHEADER 포인터 형 구조의 판독 소자로부터 14 바이트의 메모리를 직접 동적 malloc에 의해 힙 할당 된 대응하는 변수로 정의 될 수있다.
많은 코멘트를 작성하지 용서해 사용 다음 소스 코드를 붙여 넣습니다 :
#define _CRT_SECURE_NO_DEPRECATE
#include"bmp.h"
#include<string.h>
#include<stdlib.h>
#include<stdio.h>
FILE* openBmpImage(char* fileName, char* mode) {
FILE* fp;
if (strcmp(mode, "r") == 0) {
mode = "rb";
}
else if (strcmp(mode,"w") == 0) {
mode = "ab";
}
else {
//输出错误信息
fprintf(stderr,"文件打开模式:%s使用错误\n",mode);
//文件打开失败,返回空指针
return NULL;
}
if ((fp = fopen(fileName,mode)) == NULL) {
fprintf(stderr, "打开文件:%s失败\n", fileName);
return NULL;
}
return fp;
}
void closeBmpImage(FILE* fp) {
//关闭文件
fclose(fp);
//printf("已关闭文件\n");
//释放文件指针
free(fp);
//printf("已释放文件指针\n");
}
BITMAPFILEHEADER* readBmpFileHead(FILE* fp) {
//printf("%d\n", sizeof(BITMAPFILEHEADER));//这个大小是16Bytes没错
BITMAPFILEHEADER* fileHead = (BITMAPFILEHEADER*)malloc(sizeof(BITMAPFILEHEADER));
if (fileHead == NULL) {
fprintf(stderr,"内存分配失败");
}
if (fread(fileHead, sizeof(BITMAPFILEHEADER), 1, fp) != 1) {
fprintf(stderr,"文件头读取失败");
}
return fileHead;
}
BITMAPINFOHEADER* readBmpInfoHead(FILE* fp) {
//printf("%d\n", sizeof(BITMAPINFOHEADER));
BITMAPINFOHEADER* infoHead = (BITMAPINFOHEADER*)malloc(sizeof(BITMAPINFOHEADER));
if (infoHead == NULL) {
fprintf(stderr, "内存分配失败");
}
if (fread(infoHead, sizeof(BITMAPINFOHEADER), 1, fp) != 1) {
fprintf(stderr, "信息头读取失败");
}
printf("信息头大小:%d字节\n", infoHead->bHeaderSize);
printf("图片宽度:%d像素\n", infoHead->bImageWidth);
printf("图片高度:%d像素\n", infoHead->bImageHeight);
printf("颜色位数:%d位\n", infoHead->bBitsPerPixel);
printf("横向每米像素数:%d个\n", infoHead->bXpixelsPerMeter);
printf("纵向每米像素数:%d个\n", infoHead->bYpixelsPerMeter);
printf("数据块大小:%d字节\n", infoHead->bImageSize);
printf("位面数:%d\n", infoHead->bPlanes);
printf("使用颜色总数:%d个\n", infoHead->bTotalColors);
printf("重要颜色总数:%d个\n", infoHead->bImportantColors);
printf("压缩算法:%d\n", infoHead->bCompression);
return infoHead;
}
RGBDATA** readBmpDataToArr(FILE* fp) {
int i = 0, j = 0;
int width = 0, height = 0;
BITMAPFILEHEADER* fileHead = readBmpFileHead(fp);
BITMAPINFOHEADER* infoHead = readBmpInfoHead(fp);
width = infoHead->bImageWidth;
height = infoHead->bImageHeight;
RGBDATA** data = createMatrix(width,height);
//如果位数小于8则调色板有效
if (infoHead->bBitsPerPixel < 8) {
RGBQUAD* rgbQuad = (RGBQUAD*)malloc(sizeof(RGBQUAD));
if(rgbQuad == NULL){
printf("内存分配失败");
}
if (fread(rgbQuad, sizeof(rgbQuad), 1, fp) != 1) {
printf("调色板读入失败");
}
}
for (i = 0; i < height; i++) {
for (j = 0; j < width; j++) {
fread(&data[i][j], sizeof(RGBDATA), 1, fp);
}
}
return data;
}
RGBDATA** createMatrix(int width,int height) {
//动态创建二维数组
RGBDATA** Matrix;
int i;
Matrix = (RGBDATA **)malloc(sizeof(RGBDATA*) * height);
if (Matrix == NULL) {
fprintf(stderr,"内存分配失败");
return NULL;
}
for (i = 0; i < height; i++) {
Matrix[i] = (RGBDATA *)malloc(sizeof(RGBDATA) * width);
if (Matrix[i] == NULL) {
fprintf(stderr, "内存分配失败");
return NULL;
}
}
return(Matrix);
}
没有太多内容值得细说,后面是测试代码:
#include<stdio.h>
#include"bmp.h"
int main() {
//printf("%d",sizeof(unsigned short));
//printf("%d",sizeof(unsigned int));
//printf("%d",sizeof(unsigned long));
//printf("%d",sizeof(unsigned char));
FILE* fp = openBmpImage("lena.bmp","r");
//BITMAPFILEHEADER* fileHead = readBmpFileHead(fp);
//BITMAPINFOHEADER* infoHead = readBmpInfoHead(fp);
RGBDATA ** data = readBmpDataToArr(fp);
//谨慎,避免下标越界
for (int i = 0; i < 512; i++) {
for (int j = 0; j < 512; j++) {
printf("第(%d,%d)像素:[%d,%d,%d] \n ", 511-i,j+1,data[i][j].blue, data[i][j].green, data[i][j].red);
}
printf("\n");
}
closeBmpImage(fp);
getchar();
return 0;
}
运行之后可以得到这样的结果:
注意每个像素得到的三个数值分别代表b,g,r分量,和习惯的rgb是反着的。
最后要注意,大多数位图的像素信息是自下而上的,也就是说代码中得到的数组的最后一行对应图片的第一行,以此类推。。
位图读取就是这样了,下一步再考虑写入bmp文件和像素数组的处理操作。。。