为什么我的位图绘制函数在我给它的位置偏移处绘制? (C VGA 模式 12h)
Why is my bitmap drawing function plotting at an offset from the position I give it? (C VGA Mode 12h)
您好,我正在使用 DOSBOX 以 运行 程序在 12h 模式下使用 VGA 在 C 上创建位图绘图功能。我在屏幕上获取图像,但图像的开始被绘制在屏幕的中间而不是 (0,0)。谁能告诉我为什么我会出现这种行为?
我的 plot_pixel 函数工作正常。我能够在屏幕上画线和绘制像素,而不会得到我现在得到的奇怪偏移。
这说明了问题所在。
原图:
结果:
这是我的代码:
加载 BMP:
/**************************************************************************
* load_bmp *
* Loads a bitmap file into memory. *
**************************************************************************/
void load_bmp(char *file, BITMAP *b){
FILE *fp;
long index;
byte a;
word num_colors;
int x;
//SetGfxMode(0x3);
/*Opening file */
if((fp = fopen(file,"rb")) == NULL){
printf("Error al abrir el archivo %s.\n",file);
exit(1);
}
/*Validating if the image is a valid bitmap*/
if(fgetc(fp) != 'B' || fgetc(fp) != 'M'){
fclose(fp);
printf("%s is not a bitmap file. \n", file);
exit(1);
}
/*Height and width of the image
*/
fskip(fp,16);
fread(&b->width, sizeof(word),1 , fp);
fskip(fp,2);
fread(&b->height, sizeof(word),1,fp);
fskip(fp,22);
fread(&num_colors,sizeof(word),1,fp);
fskip(fp,6);
/* We are loading a 16 color image */
if(num_colors ==0) num_colors = 16;
/*Intentamos alojar memoria para la data del bitmap*/
if((b->data = (byte *) malloc((b->width*b->height))) == NULL)
{
fclose(fp);
printf("Error allocating memory for file %s.\n",file);
exit(1);
}
/*Reading pallete info*/
for(index=0;index<num_colors;index++){
b->pallete[(int)(index*3+2)] = fgetc(fp) >> 2;
b->pallete[(int)(index*3+1)] = fgetc(fp) >> 2;
b->pallete[(int)(index*3+0)] = fgetc(fp) >> 2;
//fskip(fp,240);
x = fgetc(fp);
}
/* Leyendo el bitmap*/
for(index=(b->height-1)*b->width;index>=0;index-=b->width){
for(x=0;x<b->width;x++){
b->data[index+x]=(byte)fgetc(fp);
}
}
fclose(fp);
}
绘制位图:
/**************************************************************************
* draw_transparent_bitmap *
* Draws a transparent bitmap. *
**************************************************************************/
void draw_transparent_bitmap(BITMAP *bmp,int x,int y)
{
int i,j;
unsigned long bitmap_offset = 0;
byte data;
copyMemory(double_buffer,VGA);
printf("sum");
getch();
for(j=0;j<bmp->height;j++)
{
for(i=0;i<bmp->width;i++)
{
data = bmp->data[bitmap_offset];
//if (data) double_buffer[screen_offset+x+i] = data;
if(data) plot_pixel(x+i,y+j,data);
bitmap_offset++;
}
}
}
设置托盘
void set_pallete(byte *pallete){
int i;
outp(PALETTE_INDEX,0);
for(i=0;i<16*3;i++){
outp(PALETTE_DATA,pallete[i]);
}
}
主线:
typedef struct
{
word width;
word height;
byte pallete[256*3];
byte *data;
} BITMAP;
BITMAP fondo_inicio;
load_bmp("home16.bmp",&fondo_inicio);
set_pallete(fondo_inicio.pallete);
draw_transparent_bitmap(&fondo_inicio,0,0);
我不相信您正确加载了 BMP。根据维基百科,它希望能够将此作为一个罕见的 all-but-objective 事实做到这一点,你的代码,在你检查了 'BM' 之后,假设 fskip
是 [=11] 的某种旋转=],执行以下步骤:
- 跳过告诉您 BMP 大小的 4 个字节;
- 跳过4个保留字节;
- 跳过告诉您应该从何处加载像素数据的 4 个字节(您确实应该使用并遵守);
- 假设你得到一个 Windows 3.1 辅助 header 并跳过 4 个字节告诉你它的长度(你不应该);
- 读取宽度的低两个字节;
- 跳过宽度的高两个字节;
- 读取高度的低两个字节;
- 跳过高度的高两个字节;
- skip:颜色平面数(+2 字节)、每像素位数(+2 字节)、压缩方法(+4=10)、图像大小(+4=14)、水平密度(+4= 18)、垂直密度(+4=22);
- 读取调色板大小的前两个字节;
- 跳过调色板大小的下两个字节;
- 跳过重要颜色的数量;
- 假设 header 已经结束(但您应该阅读 header 大小并在此处适当跳过);
- 读取 RGBA 调色板,假设它知道图像是 16 色,丢弃 alpha 并从 8 bits-per-channel 映射到 VGA-style 6 位;
- 假设图像数据紧跟在调色板之后(你不应该,你应该更早地阅读它的文件偏移量);
- 每个图像数据像素读取一个字节。即使您假设每个像素 4 位用于读取调色板。
如果每个像素读取整个字节提供正确的图像宽度,则您的 BMP 文件可能不是 4 位。这意味着您对 header 大小的假设肯定是错误的。几乎可以肯定,您存储的图像数据是 header 的一大块,然后是图像。首先不要跳过告诉您图像数据从哪里开始的 header 条目——阅读并使用它。否则,如果您的 plot_pixel
自动将 8 位映射为 4 位,那么如果您正在加载 256 色图像并假设仅使用最低的 16 种颜色,假设这适用于您的源图像并且存储 space 不是问题。
您好,我正在使用 DOSBOX 以 运行 程序在 12h 模式下使用 VGA 在 C 上创建位图绘图功能。我在屏幕上获取图像,但图像的开始被绘制在屏幕的中间而不是 (0,0)。谁能告诉我为什么我会出现这种行为?
我的 plot_pixel 函数工作正常。我能够在屏幕上画线和绘制像素,而不会得到我现在得到的奇怪偏移。
这说明了问题所在。
原图:
结果:
这是我的代码:
加载 BMP:
/**************************************************************************
* load_bmp *
* Loads a bitmap file into memory. *
**************************************************************************/
void load_bmp(char *file, BITMAP *b){
FILE *fp;
long index;
byte a;
word num_colors;
int x;
//SetGfxMode(0x3);
/*Opening file */
if((fp = fopen(file,"rb")) == NULL){
printf("Error al abrir el archivo %s.\n",file);
exit(1);
}
/*Validating if the image is a valid bitmap*/
if(fgetc(fp) != 'B' || fgetc(fp) != 'M'){
fclose(fp);
printf("%s is not a bitmap file. \n", file);
exit(1);
}
/*Height and width of the image
*/
fskip(fp,16);
fread(&b->width, sizeof(word),1 , fp);
fskip(fp,2);
fread(&b->height, sizeof(word),1,fp);
fskip(fp,22);
fread(&num_colors,sizeof(word),1,fp);
fskip(fp,6);
/* We are loading a 16 color image */
if(num_colors ==0) num_colors = 16;
/*Intentamos alojar memoria para la data del bitmap*/
if((b->data = (byte *) malloc((b->width*b->height))) == NULL)
{
fclose(fp);
printf("Error allocating memory for file %s.\n",file);
exit(1);
}
/*Reading pallete info*/
for(index=0;index<num_colors;index++){
b->pallete[(int)(index*3+2)] = fgetc(fp) >> 2;
b->pallete[(int)(index*3+1)] = fgetc(fp) >> 2;
b->pallete[(int)(index*3+0)] = fgetc(fp) >> 2;
//fskip(fp,240);
x = fgetc(fp);
}
/* Leyendo el bitmap*/
for(index=(b->height-1)*b->width;index>=0;index-=b->width){
for(x=0;x<b->width;x++){
b->data[index+x]=(byte)fgetc(fp);
}
}
fclose(fp);
}
绘制位图:
/**************************************************************************
* draw_transparent_bitmap *
* Draws a transparent bitmap. *
**************************************************************************/
void draw_transparent_bitmap(BITMAP *bmp,int x,int y)
{
int i,j;
unsigned long bitmap_offset = 0;
byte data;
copyMemory(double_buffer,VGA);
printf("sum");
getch();
for(j=0;j<bmp->height;j++)
{
for(i=0;i<bmp->width;i++)
{
data = bmp->data[bitmap_offset];
//if (data) double_buffer[screen_offset+x+i] = data;
if(data) plot_pixel(x+i,y+j,data);
bitmap_offset++;
}
}
}
设置托盘
void set_pallete(byte *pallete){
int i;
outp(PALETTE_INDEX,0);
for(i=0;i<16*3;i++){
outp(PALETTE_DATA,pallete[i]);
}
}
主线:
typedef struct
{
word width;
word height;
byte pallete[256*3];
byte *data;
} BITMAP;
BITMAP fondo_inicio;
load_bmp("home16.bmp",&fondo_inicio);
set_pallete(fondo_inicio.pallete);
draw_transparent_bitmap(&fondo_inicio,0,0);
我不相信您正确加载了 BMP。根据维基百科,它希望能够将此作为一个罕见的 all-but-objective 事实做到这一点,你的代码,在你检查了 'BM' 之后,假设 fskip
是 [=11] 的某种旋转=],执行以下步骤:
- 跳过告诉您 BMP 大小的 4 个字节;
- 跳过4个保留字节;
- 跳过告诉您应该从何处加载像素数据的 4 个字节(您确实应该使用并遵守);
- 假设你得到一个 Windows 3.1 辅助 header 并跳过 4 个字节告诉你它的长度(你不应该);
- 读取宽度的低两个字节;
- 跳过宽度的高两个字节;
- 读取高度的低两个字节;
- 跳过高度的高两个字节;
- skip:颜色平面数(+2 字节)、每像素位数(+2 字节)、压缩方法(+4=10)、图像大小(+4=14)、水平密度(+4= 18)、垂直密度(+4=22);
- 读取调色板大小的前两个字节;
- 跳过调色板大小的下两个字节;
- 跳过重要颜色的数量;
- 假设 header 已经结束(但您应该阅读 header 大小并在此处适当跳过);
- 读取 RGBA 调色板,假设它知道图像是 16 色,丢弃 alpha 并从 8 bits-per-channel 映射到 VGA-style 6 位;
- 假设图像数据紧跟在调色板之后(你不应该,你应该更早地阅读它的文件偏移量);
- 每个图像数据像素读取一个字节。即使您假设每个像素 4 位用于读取调色板。
如果每个像素读取整个字节提供正确的图像宽度,则您的 BMP 文件可能不是 4 位。这意味着您对 header 大小的假设肯定是错误的。几乎可以肯定,您存储的图像数据是 header 的一大块,然后是图像。首先不要跳过告诉您图像数据从哪里开始的 header 条目——阅读并使用它。否则,如果您的 plot_pixel
自动将 8 位映射为 4 位,那么如果您正在加载 256 色图像并假设仅使用最低的 16 种颜色,假设这适用于您的源图像并且存储 space 不是问题。