为什么我的位图绘制函数在我给它的位置偏移处绘制? (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 不是问题。