更难以调查一个非常奇怪的意外结果

时间:2014-08-31 05:06:46

标签: c io bmp

我之前发过关于这个问题的帖子..但问题无法解决。 所以我可以诚实地说,这是我在编程经历中遇到的最奇怪,无法解释的并发症。

问题是当我从缓冲区中绘制bmp时。 enter image description here

如果我改变图像的尺寸,例如,如果我使宽度&gt; <身高或身高>宽度,图像正常呈现。看看代码:

void bmp_bdraw (BYTE* BUFF)
{

    word WIDTH, HEIGHT, W, H; // word - unsigned short
    BYTE R, G, B; // BYTE - unsigned char

    (!BUFF || !BUFF[COUNT-1]) ? // debug1
        (error("Error in function 'bmp_bdraw'. There is no data to read from.")) : ;                  

    WIDTH = BUFF[18] + BUFF[19] * 256;
    HEIGHT = BUFF[22] + BUFF[23] * 256;
    ofs = 54;

    if(BUFF[0] != 'B' | BUFF[1] != 'M') error // debug2
        ("Warning: Data identifier error in function 'bmp_bdraw' occurred. Invalid BMP file loaded.");

    for(H=HEIGHT-1; H>=1; H--)
    {
        for(W=0; W<WIDTH; W++)
        {
            B = sgetc(BUFF); // fgetc-like function but from buff
            G = sgetc(BUFF);
            R = sgetc(BUFF);

            setpen(R, G, B, 0, 1); // sets the color, transparancy and size of the pen
            putpixel(W, H); // and puts the pixel at the right location
        }
    }

    if(W != WIDTH || H > 1) // debug3
        error("Error in function 'bmp_bdraw'. Rendering failed. The file might be damaged.");         

    if(real_fps < 11)
        error("Too low fps rate."); // debug4

我在行中注意到的是:for(H=HEIGHT-1; H>=1; H--)H>=1 在直接绘制(bmp to render)函数(100%工作并使用相同的方法)中,它是H>=0 但是..如果我将H>=1更改为H>=0,则返回缓冲区溢出错误,返回 通过sgetc函数。

3 个答案:

答案 0 :(得分:2)

  • 而不是putpixel更喜欢使用任何bitblt函数(如果可用)。
  • 扫描线结束后跳过paddding bytes(如果有)。

更新了代码

numPadBytes = WIDTH * 3;
numPadBytes %= 4;
if(0 != numPadBytes) numPadBytes = 4 - numPadBytes;

for(H=HEIGHT-1; H>=1; H--)
{
 for(W=0; W<WIDTH; W++)
 {
  B = sgetc(BUFF); // fgetc-like function but from buff
  G = sgetc(BUFF);
  R = sgetc(BUFF);

  setpen(R, G, B, 0, 1); // sets the color, transparancy and size of the pen
  putpixel(W, H); // and puts the pixel at the right location
 }
 for(tmp = 0; tmp < numPadBytes; ++tmp)
 {
  /* Ignore bytes */
  sgetc(BUFF);
 }
}

您需要将numPadBytestmp声明为您函数的本地int

答案 1 :(得分:2)

您需要在x方向上遍历位图的 stride 。位图的每一行填充为四个字节的倍数。

您的代码循环遍历宽度(* 3个字节),但行末可能有1..3个额外字节。结果是你过早地开始绘制到输出缓冲区,将第一行之外的所有内容偏向左侧。

您可以按如下方式计算步幅。使用它而不是宽度。

int stride = 4 * ((width * bytesPerPixel + 3) / 4); // in bytes

因此,阅读图像数据看起来就像这样......

unsigned char *scan0 = buf + pixel_buffer_offset;

for (int y = 0; y < height; ++y)
{
    // sets the pointer to the beginning of the yth row
    unsigned byte *row = scan0 + y * stride;

    for (int x = 0; x < width; ++x)
    { 
        unsigned char b = *row++;
        unsigned char g = *row++;
        unsigned char r = *row++;

        setpen(r, g, b, 0, 1);
        putpixel(x, y);
    }
} 

你写的任何缓冲区应该初始化为0,因为我们没有写出填充字节。如果您不想这样做,那么您将需要遍历每一行的整个步幅。  还要确保为其分配了stride * height个字节,而不是width * height * 3

答案 2 :(得分:1)

我建议只涉及一行并且不会引起头痛的事情:

ofs = ofs + WIDTH%4;

在外循环中,在内循环之后。我刚刚发现它有效..而且我不知道为什么人们提出这么多代码而不是这样做。如果其他人决定从缓冲区渲染,希望有所帮助。