BMP宽度/高度大小超过255?

时间:2014-05-12 10:44:06

标签: c bitmap bmp image-size

众所周知,每个字节都是无符号字符,表示范围为0 - 255。 我写了一个代码来编写BMP,代码可以工作..问题是当我尝试写一个宽度/高度超过255的bmp时,它显示为小于255的值。

在宽度的下一位我刚推出1并且它有效。它输出真实的(500),但我希望它也适用于高度..但它不是。图像破了。

更新:高度超过214的混乱导致损坏的bmp。我错过了什么? 这是我的代码:

typedef unsigned char  BYTE;    //1
typedef unsigned short WORD;    //2
typedef unsigned long  DWORD;   //4

typedef struct BMP_HEADER
{
    BYTE bmp_type[2];       //2
    BYTE bmp_size[4];       //4

    BYTE bmp_as[4];         //4

    BYTE bmp_offset[4];     //4
} BMP;

typedef struct DIB_HEADER
{
    BYTE dib_size[4];       //4
    DWORD dib_BMPwidth;     //4
    DWORD dib_BMPheight;        //4

    BYTE dib_BMPcplanes[2];     //2
    BYTE dib_BMPBPX[2];     //2
    BYTE dib_BIRGB[4];      //4
    BYTE dib_rawsize[4];        //4

    BYTE dib_Xresolution[4];    //4
    BYTE dib_Yresolution[4];    //4

    BYTE dib_cpalette[4];       //4
    BYTE dib_cimportant[4];     //4
} DIB;

typedef struct PIXEL_ARRAY
{
    BYTE BGR[3];            //3
} PIX;

BYTE* PAD;
DWORD padding(DWORD BMPwidth)
{
    int pitch = BMPwidth * 3;

    if (pitch % 4 != 0)
    {
        pitch += 4 - (pitch % 4);
    }

    return pitch - (BMPwidth * 3);
}

void create_bmp(char BMPname[], DWORD BMPwidth, DWORD BMPheight, WORD BMPR, WORD BMPG, WORD BMPB)
{
    // variables
    char build_name[256];
    FILE* fp;

    BMP newBMP;
    DIB newDIB;
    PIX* template;

    gedMaxGameMem = 2827465479;
    if(BMPwidth > 1 && BMPheight > 1) template = (PIX*)malloc(BMPwidth*BMPheight);
    else template = (PIX*)malloc(sizeof(PIX*)*max(BMPwidth, BMPheight));

    // make file
    sprintf(build_name, "%s.bmp", BMPname);
    fp = fopen(build_name, "wb");

    // BM
    newBMP.bmp_type[0] = 'B';
    newBMP.bmp_type[1] = 'M';   
    fwrite(&newBMP.bmp_type, 1, 2, fp);

    {
    // SIZE
    DWORD sz = (sizeof(newBMP) + sizeof(newDIB) + sizeof(template));
    fwrite(&sz, 1, 1, fp);
    }

    // Application specifics
    fwrite(&newBMP.bmp_as, 1, 4, fp);

    // offset
    newBMP.bmp_offset[0] = (sizeof(newBMP) + sizeof(newDIB));
    fwrite(&newBMP.bmp_offset, 1, 4, fp);

    //

    // DIB SIZE
    newDIB.dib_size[0] = sizeof(newDIB);
    fwrite(&newDIB.dib_size, 1, 4, fp);

    // DIB Image width
    newDIB.dib_BMPwidth = BMPwidth;
    fwrite(&newDIB.dib_BMPwidth, 1, 4, fp);

    // DIB Image height
    newDIB.dib_BMPheight = BMPheight;
    fwrite(&newDIB.dib_BMPheight, 1, 4, fp);

    // DIB Color planes
    newDIB.dib_BMPcplanes[0] = 1;
    fwrite(&newDIB.dib_BMPcplanes, 1, 2, fp);

    // DIB BMP Bits per pixel
    newDIB.dib_BMPBPX[0] = 24;
    fwrite(&newDIB.dib_BMPBPX, 1, 2, fp);

    // DIB Compression method
    fwrite(&newDIB.dib_BIRGB, 1, 4, fp);

    // DIB Raw size
    newDIB.dib_rawsize[0] = sizeof(template);
    fwrite(&newDIB.dib_rawsize, 1, 4, fp);

    // DIB Xresolution
    newDIB.dib_Xresolution[0] = 19;
    newDIB.dib_Xresolution[1] = 11;
    fwrite(&newDIB.dib_Xresolution, 1, 4, fp);

    // DIB Yresolution
    newDIB.dib_Yresolution[0] = 19;
    newDIB.dib_Yresolution[1] = 11;
    fwrite(&newDIB.dib_Yresolution, 1, 4, fp);

    // DIB Colors palette
    fwrite(&newDIB.dib_cpalette, 1, 4, fp);

    // DIB Important colors
    fwrite(&newDIB.dib_cimportant, 1, 4, fp);

    //

    {
        int i;

        for(i=0; i<BMPwidth+1; i++)
        {
            template[i].BGR[0] = BMPB;
            template[i].BGR[1] = BMPG;
            template[i].BGR[2] = BMPR;

            fwrite(template->BGR, 3, i, fp);
        }
    }

    free(template);
    fclose(fp);
}

2 个答案:

答案 0 :(得分:1)

如果你想把宽度和高度作为字节来调整,你不能只将第二个字节设置为1,你必须计算确切的值,例如:

uint32_t h = 1024;

height[0] = h & 0xff;
height[1] = (h >> 8) & 0xff;
height[2] = (h >> 16) & 0xff;
height[3] = (h >> 24) & 0xff;

& 0xff的屏蔽在这里真的是不必要的,无论如何在将数字拟合成一个字节时都已完成。)

但也许您应该首先在结构中使用更大的整数类型:

typedef struct DIB_HEADER
{
    DWORD dib_size;
    DWORD dib_BMPwidth;
    DWORD dib_BMPheight;
    WORD dib_BMPcplanes];
    ...
};

(这可能会导致字节序问题,但我认为Windows位图以Little-Endian格式存储,所以它不应该是一个问题。)

修改:进一步查看代码,我看到了一些错误:

  • 如果要为像素分配临时内存,则必须为每个像素分配3个字节,即sizeof(PIX) * BMPwidth + BMWheight。您对单行,单列和其他位图的区分是没有意义的,并且还会引入错误(即不为每个像素分配每个像素的大小。)
  • 您正在编写一种颜色的单色位图,因此您不需要创建一个巨大的临时位图;你可以一遍又一遍地写同一个像素。
  • 您在堆栈上创建BMPDIB结构;因此,它们可能未被初始化,并且在您未明确初始化的字段中存在垃圾。
  • 您不必自己编写每个字段,而是可以编写整个结构。 (但你必须取出"BM"标记,因为结构将在那里填充以使下一个字段以四字节边框开始。你也可以使用编译器选项来始终打包你的结构紧紧。)
  • 当你写出数据时,你只能在宽度上循环,但你必须在嵌套循环中遍历宽度和高度。
  • 当您使用fwrite写出数据时,您的参数是错误的:您可能想要编写fwrite(&template[i]->RGB, 3, 1, fp)。但是你的项目数是i,这意味着你从一开始就一遍又一遍地编写所有内容,但总是附加最后一个字节,如'AABABCABCDABCDE`。 (当所有像素具有相同颜色时,这无关紧要,但文件大小将关闭。)
  • BMP行数据填充为4个字节。你已为此编写了一个例程,但不要调用它。

换句话说。您的代码不适用于具有多行的数据。 : - )

以下是编写单色位图的更简单的代码版本:

void create_bmp_uni(const char *fn, int w, int h, int r, int g, int b)
{
    FILE* fp;
    DWORD rsize = (w * sizeof(PIX) + 3) / 4 * 4;
    DWORD pad = rsize - w * sizeof(PIX);
    DWORD rawsize = rsize * h * sizeof(PIX);
    BYTE zero[3] = {0};
    const char *id = "BM";

    BMP bmp = {
        2 + sizeof(BMP) + sizeof(DIB) + rawsize, 
        0,
        2 + sizeof(BMP) + sizeof(DIB)
    };

    DIB dib = {
        sizeof(DIB),
        w,
        h,
        1,
        24,
        0,
        rawsize,
        2835,
        2835,
        0,
        0
    };
    PIX pix = {b, g, r};
    int i, j;

    fp = fopen(fn, "wb");
    fwrite(id, 1, 2, fp);
    fwrite(&bmp, 1, sizeof(bmp), fp);
    fwrite(&dib, 1, sizeof(dib), fp);

    for(i = 0; i < h; i++) {
        for(j = 0; j < w; j++) {
            fwrite(&pix, sizeof(pix), 1, fp);
        }
        if (pad) fwrite(zero, 1, pad, fp);
    }

    fclose(fp);
}

(调用者必须添加.bmp后缀。还要注意BM标记是如何与BMP结构的其余部分分开编写的。)

答案 1 :(得分:0)

输出: http://i.stack.imgur.com/fqxO9.png(每次都用不同的颜色开心) 目前的代码:

typedef unsigned char  BYTE;    //1
typedef unsigned short WORD;    //2
typedef unsigned long  DWORD;   //4

typedef struct BMP_HEADER
{
    BYTE bmp_size[4];       //4

    BYTE bmp_as[4];         //4

    BYTE bmp_offset[4];     //4
} BMP;

typedef struct DIB_HEADER
{
    BYTE dib_size[4];           //4
    DWORD dib_w;                //4
    BYTE dib_h[4];              //4

    BYTE dib_BMPcplanes[2];     //2
    BYTE dib_BMPBpix[2];            //2
    BYTE dib_BIRGB[4];          //4
    BYTE dib_rawsize[4];        //4

    BYTE dib_Xresolution[4];    //4
    BYTE dib_Yresolution[4];    //4

    BYTE dib_cpalette[4];       //4
    BYTE dib_cimportant[4];     //4
} DIB;

//_______________________________________________________________________________________________//
typedef struct PIXEL_ARRAY
{
    BYTE BGR[3];            //3
} PIX;

BYTE* PAD;
DWORD padding(DWORD w)
{
    int pitch = w * 3;

    if (pitch % 4 != 0)
    {
        pitch += 4 - (pitch % 4);
    }

    return pitch - (w * 3);
}

DWORD row_sz(WORD BMPBpix, DWORD w)
{
    return ((BMPBpix*w+31)/32)*4;
}

void create_bmp(char BMPname[], DWORD w, DWORD h, BYTE R, BYTE G, BYTE B)
{
    // variables
    char build_name[256];
    FILE* fp;

    BMP newBMP;
    DIB newDIB;
    PIX* pix;

    DWORD rsize = (w * sizeof(PIX) + 3) / 4 * 4;
    DWORD pad = rsize - w * sizeof(PIX);
    DWORD rawsize = rsize * h * sizeof(PIX);
    BYTE zero[3] = {0};
    const char *id = "BM";
    int i, j;

    gedMaxGameMem = 2827465479;
    if(w > 1 && h > 1) pix = (PIX*)malloc(w*h);
    else pix = (PIX*)malloc(sizeof(PIX*)*max(w, h));

    // make file
    sprintf(build_name, "%s.bmp", BMPname);
    fp = fopen(build_name, "wb");

    // BM
    fwrite(id, 1, 2, fp);

    // SIZE
    newBMP.bmp_size[0] = (sizeof(newBMP) + sizeof(newDIB) + sizeof(pix));
    fwrite(&newBMP.bmp_size, 1, 4, fp);

    // Application specifics
    fwrite(&newBMP.bmp_as, 1, 4, fp);

    // offset
    newBMP.bmp_offset[0] = (sizeof(newBMP) + sizeof(newDIB));
    fwrite(&newBMP.bmp_offset, 1, 4, fp);

    //

    // DIB SIZE
    newDIB.dib_size[0] = sizeof(newDIB);
    fwrite(&newDIB.dib_size, 1, 4, fp);

    // DIB Image width
    newDIB.dib_w = w;
    fwrite(&newDIB.dib_w, 1, 4, fp);

    // DIB Image height
    newDIB.dib_h[0] = h;
    fwrite(&newDIB.dib_h, 1, 4, fp);

    // DIB Color planes
    newDIB.dib_BMPcplanes[0] = 1;
    fwrite(&newDIB.dib_BMPcplanes, 1, 2, fp);

    // DIB BMP Bits per pixel
    newDIB.dib_BMPBpix[0] = 24;
    fwrite(&newDIB.dib_BMPBpix, 1, 2, fp);

    // DIB Compression method
    fwrite(&newDIB.dib_BIRGB, 1, 4, fp);

    // DIB Raw size
    newDIB.dib_rawsize[0] = sizeof(pix);
    fwrite(&newDIB.dib_rawsize, 1, 4, fp);

    // DIB Xresolution
    newDIB.dib_Xresolution[0] = 19;
    newDIB.dib_Xresolution[1] = 11;
    fwrite(&newDIB.dib_Xresolution, 1, 4, fp);

    // DIB Yresolution
    newDIB.dib_Yresolution[0] = 19;
    newDIB.dib_Yresolution[1] = 11;
    fwrite(&newDIB.dib_Yresolution, 1, 4, fp);

    // DIB Colors palette
    fwrite(&newDIB.dib_cpalette, 1, 4, fp);

    // DIB Important colors
    fwrite(&newDIB.dib_cimportant, 1, 4, fp);

    //

    for(i = 0; i < h; i++) 
    {
        for(j = 0; j < w; j++) 
        {
            fwrite(&pix, sizeof(pix), 1, fp);
        }
        if (pad) fwrite(zero, 1, pad, fp);
    }
    fclose(fp);
}