2010-04-16 45 views
33

在我的算法中,我需要创建信息输出。我必须在bmp文件中编写布尔矩阵。 它必须是单色图像,如果此元素上的矩阵为真,则像素为白色。 主要问题是bmp头和如何写这个。在没有其他库的情况下在纯C/C++中编写BMP图像

+1

您可以检查http://qdbmp.sourceforge.net/实现细节:)。 – Marco 2013-12-10 14:28:26

+0

也许用于访问者谷歌搜索类似的概念是我几乎相关的问题和答案在这里:http://stackoverflow.com/questions/17918978/plot-an-array-into-bitmap-in-cc-for-thermal-printer – 2013-12-28 08:46:27

回答

20

没有使用任何其他库,你可以看看BMP file format。我已经在过去实现了它,并且可以在没有太多工作的情况下完成。

位图文件结构

每个位图文件含有 位图文件头,一个 位图信息头,颜色 表,并且字节的阵列 定义位图比特。该文件有 以下格式:

BITMAPFILEHEADER bmfh;
BITMAPINFOHEADER bmih;
RGBQUAD aColors [];
BYTE aBitmapBits [];

...查看文件格式的详细信息

+0

谢谢。这似乎太好描述。 – 2010-04-16 16:21:29

+1

如果你的处理器不是x86处理器,记得把所有东西都写出来。 – 2010-04-16 16:21:40

+0

我有x86谢谢。 – 2010-04-16 16:25:39

6

注意,线由下往上,而不是周围的其他方式保存。

此外,扫描线必须具有四倍的字节长度的倍数,您应该在行的末尾插入填充字节以确保这一点。

+2

我没有看到你写的东西。 – 2010-04-16 16:22:23

+15

别担心,你会一旦实际尝试实现这一点。 – 2010-04-16 16:32:24

+1

@Ben,因为大多数真实世界的图像已经是4倍的倍数,所以很容易错过测试中的四倍数要求。 – 2011-09-14 21:12:55

41

看看这是否适合你... 在这段代码中,我有3个二维数组,叫做红色,绿色和蓝色。每一个都是大小[宽度] [高度],每个元素对应一个像素 - 我希望这是有道理的!

FILE *f; 
unsigned char *img = NULL; 
int filesize = 54 + 3*w*h; //w is your image width, h is image height, both int 

img = (unsigned char *)malloc(3*w*h); 
memset(img,0,3*w*h); 

for(int i=0; i<w; i++) 
{ 
    for(int j=0; j<h; j++) 
    { 
     x=i; y=(h-1)-j; 
     r = red[i][j]*255; 
     g = green[i][j]*255; 
     b = blue[i][j]*255; 
     if (r > 255) r=255; 
     if (g > 255) g=255; 
     if (b > 255) b=255; 
     img[(x+y*w)*3+2] = (unsigned char)(r); 
     img[(x+y*w)*3+1] = (unsigned char)(g); 
     img[(x+y*w)*3+0] = (unsigned char)(b); 
    } 
} 

unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; 
unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; 
unsigned char bmppad[3] = {0,0,0}; 

bmpfileheader[ 2] = (unsigned char)(filesize ); 
bmpfileheader[ 3] = (unsigned char)(filesize>> 8); 
bmpfileheader[ 4] = (unsigned char)(filesize>>16); 
bmpfileheader[ 5] = (unsigned char)(filesize>>24); 

bmpinfoheader[ 4] = (unsigned char)(  w ); 
bmpinfoheader[ 5] = (unsigned char)(  w>> 8); 
bmpinfoheader[ 6] = (unsigned char)(  w>>16); 
bmpinfoheader[ 7] = (unsigned char)(  w>>24); 
bmpinfoheader[ 8] = (unsigned char)(  h ); 
bmpinfoheader[ 9] = (unsigned char)(  h>> 8); 
bmpinfoheader[10] = (unsigned char)(  h>>16); 
bmpinfoheader[11] = (unsigned char)(  h>>24); 

f = fopen("img.bmp","wb"); 
fwrite(bmpfileheader,1,14,f); 
fwrite(bmpinfoheader,1,40,f); 
for(int i=0; i<h; i++) 
{ 
    fwrite(img+(w*(h-i-1)*3),3,w,f); 
    fwrite(bmppad,1,(4-(w*3)%4)%4,f); 
} 

free(img); 
fclose(f); 
+10

嗯,评论不会伤害。 – 2011-09-14 19:12:54

+1

确实如此,但整个代码是自我解释的。它的工作原理。把它放在'main()'函数内部并初始化所有变量。并做了! ;) – sinner 2012-06-15 18:01:08

+7

任何人都可以告诉代码中的'yres'吗? – 2013-01-17 13:25:04

5

这是一个适用于我的代码的C++变体。注意我必须改变大小计算来考虑行填充。

// mimeType = "image/bmp"; 

unsigned char file[14] = { 
    'B','M', // magic 
    0,0,0,0, // size in bytes 
    0,0, // app data 
    0,0, // app data 
    40+14,0,0,0 // start of data offset 
}; 
unsigned char info[40] = { 
    40,0,0,0, // info hd size 
    0,0,0,0, // width 
    0,0,0,0, // heigth 
    1,0, // number color planes 
    24,0, // bits per pixel 
    0,0,0,0, // compression is none 
    0,0,0,0, // image bits size 
    0x13,0x0B,0,0, // horz resoluition in pixel/m 
    0x13,0x0B,0,0, // vert resolutions (0x03C3 = 96 dpi, 0x0B13 = 72 dpi) 
    0,0,0,0, // #colors in pallete 
    0,0,0,0, // #important colors 
    }; 

int w=waterfallWidth; 
int h=waterfallHeight; 

int padSize = (4-(w*3)%4)%4; 
int sizeData = w*h*3 + h*padSize; 
int sizeAll = sizeData + sizeof(file) + sizeof(info); 

file[ 2] = (unsigned char)(sizeAll ); 
file[ 3] = (unsigned char)(sizeAll>> 8); 
file[ 4] = (unsigned char)(sizeAll>>16); 
file[ 5] = (unsigned char)(sizeAll>>24); 

info[ 4] = (unsigned char)(w ); 
info[ 5] = (unsigned char)(w>> 8); 
info[ 6] = (unsigned char)(w>>16); 
info[ 7] = (unsigned char)(w>>24); 

info[ 8] = (unsigned char)(h ); 
info[ 9] = (unsigned char)(h>> 8); 
info[10] = (unsigned char)(h>>16); 
info[11] = (unsigned char)(h>>24); 

info[20] = (unsigned char)(sizeData ); 
info[21] = (unsigned char)(sizeData>> 8); 
info[22] = (unsigned char)(sizeData>>16); 
info[23] = (unsigned char)(sizeData>>24); 

stream.write((char*)file, sizeof(file)); 
stream.write((char*)info, sizeof(info)); 

unsigned char pad[3] = {0,0,0}; 

for (int y=0; y<h; y++) 
{ 
    for (int x=0; x<w; x++) 
    { 
     long red = lround(255.0 * waterfall[x][y]); 
     if (red < 0) red=0; 
     if (red > 255) red=255; 
     long green = red; 
     long blue = red; 

     unsigned char pixel[3]; 
     pixel[0] = blue; 
     pixel[1] = green; 
     pixel[2] = red; 

     stream.write((char*)pixel, 3); 
    } 
    stream.write((char*)pad, padSize); 
} 
+1

padsize看起来不正确;我相信它应该是:'int padSize =(4 - 3 * w%4)%4;' – etienne 2014-06-23 14:21:08

+3

这里是什么瀑布[] []? – manujmv 2014-07-23 11:25:18

1

如果使用上述C++函数在图像中间切换了奇怪的颜色,请务必以二进制模式打开流出: imgFile.open(filename, std::ios_base::out | std::ios_base::binary);
否则,Windows将不需要的字符插入文件中间! (撞了在这个问题上我的头几个小时)

参阅相关的问题在这里:Why does ofstream insert a 0x0D byte before 0x0A?

6

这是最好的低水平例如我知道,通过Evercat写的。从 https://en.wikipedia.org/wiki/User:Evercat/Buddhabrot.c

void drawbmp (char * filename) { 

unsigned int headers[13]; 
FILE * outfile; 
int extrabytes; 
int paddedsize; 
int x; int y; int n; 
int red, green, blue; 

extrabytes = 4 - ((WIDTH * 3) % 4);     // How many bytes of padding to add to each 
                // horizontal line - the size of which must 
                // be a multiple of 4 bytes. 
if (extrabytes == 4) 
    extrabytes = 0; 

paddedsize = ((WIDTH * 3) + extrabytes) * HEIGHT; 

// Headers... 
// Note that the "BM" identifier in bytes 0 and 1 is NOT included in these "headers". 

headers[0] = paddedsize + 54;  // bfSize (whole file size) 
headers[1] = 0;     // bfReserved (both) 
headers[2] = 54;     // bfOffbits 
headers[3] = 40;     // biSize 
headers[4] = WIDTH; // biWidth 
headers[5] = HEIGHT; // biHeight 

// Would have biPlanes and biBitCount in position 6, but they're shorts. 
// It's easier to write them out separately (see below) than pretend 
// they're a single int, especially with endian issues... 

headers[7] = 0;     // biCompression 
headers[8] = paddedsize;   // biSizeImage 
headers[9] = 0;     // biXPelsPerMeter 
headers[10] = 0;     // biYPelsPerMeter 
headers[11] = 0;     // biClrUsed 
headers[12] = 0;     // biClrImportant 

outfile = fopen(filename, "wb"); 

// 
// Headers begin... 
// When printing ints and shorts, we write out 1 character at a time to avoid endian issues. 
// 

fprintf(outfile, "BM"); 

for (n = 0; n <= 5; n++) 
{ 
    fprintf(outfile, "%c", headers[n] & 0x000000FF); 
    fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); 
    fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); 
    fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24); 
} 

// These next 4 characters are for the biPlanes and biBitCount fields. 

fprintf(outfile, "%c", 1); 
fprintf(outfile, "%c", 0); 
fprintf(outfile, "%c", 24); 
fprintf(outfile, "%c", 0); 

for (n = 7; n <= 12; n++) 
{ 
    fprintf(outfile, "%c", headers[n] & 0x000000FF); 
    fprintf(outfile, "%c", (headers[n] & 0x0000FF00) >> 8); 
    fprintf(outfile, "%c", (headers[n] & 0x00FF0000) >> 16); 
    fprintf(outfile, "%c", (headers[n] & (unsigned int) 0xFF000000) >> 24); 
} 

// 
// Headers done, now write the data... 
// 

for (y = HEIGHT - 1; y >= 0; y--)  // BMP image format is written from bottom to top... 
{ 
    for (x = 0; x <= WIDTH - 1; x++) 
    { 

     red = reduce(redcount[x][y] + COLOUR_OFFSET) * red_multiplier; 
     green = reduce(greencount[x][y] + COLOUR_OFFSET) * green_multiplier; 
     blue = reduce(bluecount[x][y] + COLOUR_OFFSET) * blue_multiplier; 

     if (red > 255) red = 255; if (red < 0) red = 0; 
     if (green > 255) green = 255; if (green < 0) green = 0; 
     if (blue > 255) blue = 255; if (blue < 0) blue = 0; 

     // Also, it's written in (b,g,r) format... 

     fprintf(outfile, "%c", blue); 
     fprintf(outfile, "%c", green); 
     fprintf(outfile, "%c", red); 
    } 
    if (extrabytes)  // See above - BMP lines must be of lengths divisible by 4. 
    { 
     for (n = 1; n <= extrabytes; n++) 
     { 
     fprintf(outfile, "%c", 0); 
     } 
    } 
} 

fclose(outfile); 
return; 
} 


drawbmp(filename); 
+0

只有链接回答不好,你应该提供一些关于答案的信息。 – 2015-08-15 17:48:02

+0

@kevstev不要编辑,是一个可行的解决方案。如果你想适应这个程序在这个线程的新答案中发布一个新版本 – 2017-01-25 14:57:50

1

复制我主编拉尔夫的HTP代码,以便它会编译(海合会,运行Ubuntu 16.04 LTS)。这只是一个初始化变量的问题。

int w = 100; /* Put here what ever width you want */ 
    int h = 100; /* Put here what ever height you want */ 
    int red[w][h]; 
    int green[w][h]; 
    int blue[w][h]; 


    FILE *f; 
    unsigned char *img = NULL; 
    int filesize = 54 + 3*w*h; //w is your image width, h is image height, both int 
    if(img) 
      free(img); 
    img = (unsigned char *)malloc(3*w*h); 
    memset(img,0,sizeof(img)); 
    int x; 
    int y; 
    int r; 
    int g; 
    int b; 

    for(int i=0; i<w; i++) 
    { 
      for(int j=0; j<h; j++) 
      { 
        x=i; y=(h-1)-j; 
        r = red[i][j]*255; 
        g = green[i][j]*255; 
        b = blue[i][j]*255; 
        if (r > 255) r=255; 
        if (g > 255) g=255; 
        if (b > 255) b=255; 
        img[(x+y*w)*3+2] = (unsigned char)(r); 
        img[(x+y*w)*3+1] = (unsigned char)(g); 
        img[(x+y*w)*3+0] = (unsigned char)(b); 
      } 
    } 

    unsigned char bmpfileheader[14] = {'B','M', 0,0,0,0, 0,0, 0,0, 54,0,0,0}; 
    unsigned char bmpinfoheader[40] = {40,0,0,0, 0,0,0,0, 0,0,0,0, 1,0, 24,0}; 
    unsigned char bmppad[3] = {0,0,0}; 

    bmpfileheader[ 2] = (unsigned char)(filesize ); 
    bmpfileheader[ 3] = (unsigned char)(filesize>> 8); 
    bmpfileheader[ 4] = (unsigned char)(filesize>>16); 
    bmpfileheader[ 5] = (unsigned char)(filesize>>24); 

    bmpinfoheader[ 4] = (unsigned char)(  w ); 
    bmpinfoheader[ 5] = (unsigned char)(  w>> 8); 
    bmpinfoheader[ 6] = (unsigned char)(  w>>16); 
    bmpinfoheader[ 7] = (unsigned char)(  w>>24); 
    bmpinfoheader[ 8] = (unsigned char)(  h ); 
    bmpinfoheader[ 9] = (unsigned char)(  h>> 8); 
    bmpinfoheader[10] = (unsigned char)(  h>>16); 
    bmpinfoheader[11] = (unsigned char)(  h>>24); 

    f = fopen("img.bmp","wb"); 
    fwrite(bmpfileheader,1,14,f); 
    fwrite(bmpinfoheader,1,40,f); 
    for(int i=0; i<h; i++) 
    { 
      fwrite(img+(w*(h-i-1)*3),3,w,f); 
      fwrite(bmppad,1,(4-(w*3)%4)%4,f); 
    } 
    fclose(f); 
2

清洁C代码为位图(BMP)图像生成

生成图像:

bitmap image


的代码不使用其他任何库比stdio.h中。因此,代码可以很容易地与C系列的其他语言结合使用,如C++,C#,Java。


#include <stdio.h> 

const int bytesPerPixel = 3; /// red, green, blue 
const int fileHeaderSize = 14; 
const int infoHeaderSize = 40; 

void generateBitmapImage(unsigned char *image, int height, int width, char* imageFileName); 
unsigned char* createBitmapFileHeader(int height, int width); 
unsigned char* createBitmapInfoHeader(int height, int width); 


int main(){ 
    int height = 541; 
    int width = 800; 
    unsigned char image[height][width][bytesPerPixel]; 
    char* imageFileName = "bitmapImage.bmp"; 

    int i, j; 
    for(i=0; i<height; i++){ 
     for(j=0; j<width; j++){ 
      image[i][j][2] = (unsigned char)((double)i/height*255); ///red 
      image[i][j][1] = (unsigned char)((double)j/width*255); ///green 
      image[i][j][0] = (unsigned char)(((double)i+j)/(height+width)*255); ///blue 
     } 
    } 

    generateBitmapImage((unsigned char *)image, height, width, imageFileName); 
} 


void generateBitmapImage(unsigned char *image, int height, int width, char* imageFileName){ 

    unsigned char* fileHeader = createBitmapFileHeader(height, width); 
    unsigned char* infoHeader = createBitmapInfoHeader(height, width); 
    unsigned char padding[3] = {0, 0, 0}; 
    int paddingSize = (4-(width*bytesPerPixel)%4)%4; 

    FILE* imageFile = fopen(imageFileName, "wb"); 

    fwrite(fileHeader, 1, fileHeaderSize, imageFile); 
    fwrite(infoHeader, 1, infoHeaderSize, imageFile); 

    int i; 
    for(i=0; i<height; i++){ 
     fwrite(image+(i*width*bytesPerPixel), bytesPerPixel, width, imageFile); 
     fwrite(padding, 1, paddingSize, imageFile); 
    } 

    fclose(imageFile); 
} 

unsigned char* createBitmapFileHeader(int height, int width){ 
    int fileSize = fileHeaderSize + infoHeaderSize + bytesPerPixel*height*width; 

    static unsigned char fileHeader[] = { 
     0,0, /// signature 
     0,0,0,0, /// image file size in bytes 
     0,0,0,0, /// reserved 
     0,0,0,0, /// start of pixel array 
    }; 

    fileHeader[ 0] = (unsigned char)('B'); 
    fileHeader[ 1] = (unsigned char)('M'); 
    fileHeader[ 2] = (unsigned char)(fileSize ); 
    fileHeader[ 3] = (unsigned char)(fileSize>> 8); 
    fileHeader[ 4] = (unsigned char)(fileSize>>16); 
    fileHeader[ 5] = (unsigned char)(fileSize>>24); 
    fileHeader[10] = (unsigned char)(fileHeaderSize + infoHeaderSize); 

    return fileHeader; 
} 

unsigned char* createBitmapInfoHeader(int height, int width){ 
    static unsigned char infoHeader[] = { 
     0,0,0,0, /// header size 
     0,0,0,0, /// image width 
     0,0,0,0, /// image height 
     0,0, /// number of color planes 
     0,0, /// bits per pixel 
     0,0,0,0, /// compression 
     0,0,0,0, /// image size 
     0,0,0,0, /// horizontal resolution 
     0,0,0,0, /// vertical resolution 
     0,0,0,0, /// colors in color table 
     0,0,0,0, /// important color count 
    }; 

    infoHeader[ 0] = (unsigned char)(infoHeaderSize); 
    infoHeader[ 4] = (unsigned char)(width ); 
    infoHeader[ 5] = (unsigned char)(width>> 8); 
    infoHeader[ 6] = (unsigned char)(width>>16); 
    infoHeader[ 7] = (unsigned char)(width>>24); 
    infoHeader[ 8] = (unsigned char)(height ); 
    infoHeader[ 9] = (unsigned char)(height>> 8); 
    infoHeader[10] = (unsigned char)(height>>16); 
    infoHeader[11] = (unsigned char)(height>>24); 
    infoHeader[12] = (unsigned char)(1); 
    infoHeader[14] = (unsigned char)(bytesPerPixel*8); 

    return infoHeader; 
} 
相关问题