C 对一个非常奇怪的意外结果进行更严格的调查
我以前发过关于那个问题的帖子。。但问题无法解决。 因此,我可以诚实地说,这是我在编程经验中遇到的最奇怪、无法解释的复杂情况 问题是当我从缓冲区中绘制bmp时。 如果我更改图像的尺寸(例如,如果我使宽度>高度或高度>宽度),图像将正常渲染。看看代码: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
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
声明在哪里?您