C 对一个非常奇怪的意外结果进行更严格的调查

C 对一个非常奇怪的意外结果进行更严格的调查,c,io,bmp,C,Io,Bmp,我以前发过关于那个问题的帖子。。但问题无法解决。 因此,我可以诚实地说,这是我在编程经验中遇到的最奇怪、无法解释的复杂情况 问题是当我从缓冲区中绘制bmp时。 如果我更改图像的尺寸(例如,如果我使宽度>高度或高度>宽度),图像将正常渲染。看看代码: void bmp_bdraw (BYTE* BUFF) { word WIDTH, HEIGHT, W, H; // word - unsigned short BYTE R, G, B; // BYTE - unsigned c

我以前发过关于那个问题的帖子。。但问题无法解决。 因此,我可以诚实地说,这是我在编程经验中遇到的最奇怪、无法解释的复杂情况

问题是当我从缓冲区中绘制bmp时。

如果我更改图像的尺寸(例如,如果我使宽度>高度或高度>宽度),图像将正常渲染。看看代码:

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
void bmp\u bdraw(字节*BUFF)
{
字宽,字高,W,H;//字-无符号短
字节R,G,B;//字节-无符号字符
(!BUFF | |!BUFF[COUNT-1])?//调试1
(错误(“函数“bmp_bdraw”中的错误。没有可读取的数据”):;
宽度=BUFF[18]+BUFF[19]*256;
高度=BUFF[22]+BUFF[23]*256;
ofs=54;
if(BUFF[0]!=“B”| BUFF[1]!=“M”)错误//调试2
(“警告:函数'bmp_bdraw'中出现数据标识符错误。加载的bmp文件无效。”);
对于(H=高度-1;H>=1;H--)
{
对于(W=0;W 1)//debug3
错误(“函数“bmp_bdraw”中出错。渲染失败。文件可能已损坏。”);
如果(真实fps<11)
错误(“fps速率太低。”);//调试4
我在这行中注意到:
for(H=HEIGHT-1;H>=1;H--)
H>=1
在直接绘制(bmp渲染)功能中(100%工作并使用相同的方法),它是
H>=0
但是,如果我将
H>=1
更改为
H>=0
,它将返回一个缓冲区溢出错误,返回 通过
sgetc
功能。

  • 如果可用,您可以使用任何bitblt函数,而不是putpixel
  • 扫描线结束后跳过(如果有)
更新代码

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);
 }
}
numPadBytes=宽度*3;
numPadBytes%=4;
如果(0!=numPadBytes)numPadBytes=4-numPadBytes;
对于(H=高度-1;H>=1;H--)
{
对于(W=0;W
  • 如果可用,您可以使用任何bitblt函数,而不是putpixel
  • 扫描线结束后跳过(如果有)
更新代码

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);
 }
}
numPadBytes=宽度*3;
numPadBytes%=4;
如果(0!=numPadBytes)numPadBytes=4-numPadBytes;
对于(H=高度-1;H>=1;H--)
{

对于(W=0;W,您需要在x方向上循环位图的跨距。位图的每一行填充为四个字节的倍数

您的代码在宽度(*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);
    }
} 
无符号字符*scan0=buf+像素缓冲区偏移量;
对于(int y=0;y
无论您要写入哪个缓冲区,都应该初始化为0,因为我们没有写入填充字节。如果您不想这样做,则需要在每行的整个步幅中循环。
另外,请确保已为其分配
stride*height
字节,而不是
width*height*3

您需要在x方向上循环浏览位图的步幅。位图的每行填充为四个字节的倍数

您的代码在宽度(*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);
    }
} 
无符号字符*scan0=buf+像素缓冲区偏移量;
对于(int y=0;y
无论您要写入哪个缓冲区,都应该初始化为0,因为我们没有写入填充字节。如果您不想这样做,则需要在每行的整个步幅中循环。
另外,请确保您已为其分配了
stride*height
字节,而不是
width*height*3

我建议只涉及一行且不会引起头痛的内容:

ofs = ofs + WIDTH%4;

在外循环中,在内循环之后。我刚刚发现这是可行的。我不知道为什么人们在这样做时会显示这么多代码。如果其他人决定从缓冲区进行渲染,希望这会有所帮助。

我建议只涉及一行代码,并且不会引起麻烦:

ofs = ofs + WIDTH%4;

在外循环中,在内循环之后。我刚刚发现这是可行的。我不知道为什么人们在这样做时会显示这么多代码。如果其他人决定从缓冲区渲染,希望这会有所帮助。

抱歉,我不能使用任何其他函数,但是
putpixel
该函数在任何地方都可以正常工作。例如,在同一个函数中,但是用于直接从bmp中绘制。你说的扫描线是什么?如果bmp的宽度是4的倍数,你会得到正确的输出吗?测试一幅宽度不是4的倍数的图像,结果失败。但是如果是4的倍数,结果很好。这意味着它与填充字节有关。是的,但我不理解d为什么..为什么直接绘图功能运行良好,而该功能运行不正常。区别在哪里。但是
tmp
声明在哪里?您