显示BMP图象的程序

来源:互联网 发布:网络平板液晶电视机 编辑:程序博客网 时间:2024/04/29 14:33
显示BMP图象的程序       640*480 256 色 .BMP 文件显示程序,可以浏览、同时显示 4 幅图象,也可以 在屏幕上开一个窗口显示 .BMP 图象,并可以使用上下左右箭头键、PageUp/PageDown、Ctrl+Left、Ctrl+Right键浏览整幅图象,在S3、ATI等VGA卡上 调试通过

/*
   SHOWBMP.C --- Show .BMP files images for SVGA 640*480(256/16) mode
   M.L.Y  2000.9, 2000.12

   Please compile this file by Borland C++ 3.1:
     BCC -ml SHOWBMP.C
*/

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <dir.h>
#include "GCFSVGA.C"

typedef struct
{
  int  bfType;            /* 文件类型, 必须为 "BM" (0x4D42) */
  long bfSize;            /* 文件的大小(字节) */
  int  bfReserved1;       /* 保留, 必须为 0 */
  int  bfReserved2;       /* 保留, 必须为 0 */
  long bfoffBits;         /* 位图阵列相对于文件头的偏移量(字节) */
} BITMAPFILEHEADER;       /* 文件头结构 */

typedef struct
{
  long biSize;            /* size of BITMAPINFOHEADER */
  long biWidth;           /* 位图宽度(像素) */
  long biHeight;          /* 位图高度(像素) */
  int  biPlanes;          /* 目标设备的位平面数, 必须置为1 */
  int  biBitCount;        /* 每个像素的位数, 1,4,8或24 */
  long biCompress;        /* 位图阵列的压缩方法,0=不压缩 */
  long biSizeImage;       /* 图像大小(字节) */
  long biXPelsPerMeter;   /* 目标设备水平每米像素个数 */
  long biYPelsPerMeter;   /* 目标设备垂直每米像素个数 */
  long biClrUsed;         /* 位图实际使用的颜色表的颜色数 */
  long biClrImportant;    /* 重要颜色索引的个数 */
} BITMAPINFOHEADER;       /* 位图信息头结构 */

typedef struct
{
  USGC rgbBlue;
  USGC rgbGreen;
  USGC rgbRed;
  USGC rgbReserved;
} RGBQUAD;

BITMAPFILEHEADER FileHead;
BITMAPINFOHEADER InfoHead;
int  gl_index_color = NO;  /* first .BMP file */

/* ------------------------------------------------------------------------- */
int  read_palette(FILE *fp, USGC pal[][3], int colornum)
/*
   将文件(指针fp)的当前位置的调色板数据读到 pal 中,colornum 是颜色数
*/
{
  int  i;

  memset(pal, 0, 3*colornum);
  for(i = 0; i < colornum; i++)
  {
    pal[i][2] = (char)fgetc(fp) >> 2;  /* Blue */
    pal[i][1] = (char)fgetc(fp) >> 2;  /* Green */
    pal[i][0] = (char)fgetc(fp) >> 2;  /* Red */
    fgetc(fp);
  }
  return 0;
}

/* ------------------------------------------------------------------------- */
int  show_bmp(FILE *fp, int color_index[256])
/*
   按当前参数重新显示 .BMP 文件(文件指针 fp) (2色,16色或256色)
   若是非第一幅图象,以第一幅图象调色板为准,颜色号索引表为 color_index
   返回:  0 --- ok
         -1 --- 显示图象时读文件出错
*/
{
  int  y, n, i, j, k;
  long file_pos;
  USGC buf[4096];         /* 文件中读出的一行图象 */
  USGC linebuf[4096];     /* line buffer (一行图象) */

  if(gl_browse_bmp == 1 && gn_x0 == gn_x0_old && gn_y0 == gn_y0_old)
    return 0;
  gn_x0_old = gn_x0;
  gn_y0_old = gn_y0;

  for(y = 0; y < gn_win_h; y++)
  {
    memset(linebuf, 0, 640);

    if(gn_x0 >= gn_pic_w || y + gn_y0 >= gn_pic_h) n = 0;
    else if(gn_x0 + gn_win_w > gn_pic_w) n = gn_pic_w - gn_x0;
    else n = gn_win_w;

    /* 从文件头开始算: */
/*
    file_pos = FileHead.bfoffBits +
               (long)(gn_pic_h - 1 - y - gn_y0) * gn_line_bytes + gn_x0;
*/
    file_pos = FileHead.bfoffBits +
               (long)(gn_pic_h - 1 - y - gn_y0) * gn_line_bytes;

    /* 大部分书上是从文件尾开始算, 正向偏移: */
    /*  file_pos = FileHead.bfSize -
                   (long)(y + gn_y0 + 1) * gn_line_bytes + gn_x0; */

    if(n > 0)
    {
      fseek(fp, file_pos, SEEK_SET);
/* 如果采用反向偏移: */
/*    fseek(fp, -file_pos, SEEK_END); */
/*
      if(fread(linebuf, 1, n, fp) != n)
        return -1;
*/
      if(fread(buf, 1, gn_line_bytes, fp) != gn_line_bytes)
        return -1;
      for(i = 0, j = 0; i < gn_line_bytes; i++)
      {
        for(k = 0; k < gn_pix_pb; k++)
        {
          linebuf[j++] = (buf[i] & gc_base) >> (8 - gn_bit_pp);
          buf[i] <<= gn_bit_pp;
        }
      }

      if(gl_index_color == YES)
      {
        for(i = 0; i < n; i++)
          linebuf[i] = color_index[linebuf[i>;
      }
    }
/*
    VESA_putimage_256(y + gn_win_top, gn_win_left, linebuf, gn_win_w,
                      IMG_COPY_PUT);
*/
    if(gn_vid_color_num == 16)
      VGA_putimage_16(y + gn_win_top, gn_win_left, linebuf+gn_x0, gn_win_w,
                      IMG_COPY_PUT);
    else /* gn_vid_color_num = 256 */
      VESA_putimage_256(y + gn_win_top, gn_win_left, linebuf+gn_x0, gn_win_w,
                        IMG_COPY_PUT);
/* 下列语句在 640*480*256 方式下因 buffer 超过 64K , 所以是错误的:
    p = MK_FP(0xA000, (y + gn_win_top) * gn_MAX_X_RES + gn_win_left);
    memmove(p, linebuf, gn_win_w);
*/
  }
  return 0;
}

/* ------------------------------------------------------------------------- */
int  show_bmp_img(char *bmpfile, int wy0, int wx0, int wy, int wx)
/*
   在 wy0 行 wx0 列开始显示 bmpfile 文件的图象,窗口高 wy、宽 wx

   同屏幕显示多幅图象有调色板问题:
   本程序使用第 1 幅图象的调色板,并计算出调色板各种颜色的灰度值,
   对后面的图象其调色板某种颜色的灰度值与第一幅图象调色板中某种颜
   色的灰度值最接近,就用第一幅图象调色板的那种颜色代替它,生成颜
   色号索引表 color_index。
   由于图象中可能有多种颜色被同一种屏幕颜色替代回产生较大的失真,
   所以又要把屏幕调色板中的这种颜色改为这些颜色的平均值。

   返回:  0 --- ok
         -1 --- 打开文件出错
         -2 --- 读文件头出错
         -3 --- 非 .BMP 文件
         -4 --- 读文件信息头出错
         -5 --- 本程序不支持压缩文件
         -6 --- 颜色数本程序不支持(本程序只处理2色,16色或256色图象)
         -7 --- 图象超宽(>4096)
         -8 --- 显示图象时读文件出错
*/
{
  FILE *fp;
  register int i, j, k;
  int  color2;
  USGC pal2[256][3];  /* palette data */
  float gray2[256];
  int  c_index[256];
  float pre_gray_val, gray_val;
  int  rr, gg, bb;

  if((fp = fopen(bmpfile, "rb")) == NULL)
    return(-1);
  if(fread((char *)&FileHead,1,sizeof(BITMAPFILEHEADER),fp) !=
     sizeof(BITMAPFILEHEADER))
  {
    fclose(fp);
    return -2;
  }
  if(*((char *)&(FileHead.bfType)) != ''B'' ||
     *((char *)&(FileHead.bfType) + 1) != ''M'')
  {
    fclose(fp);
    return -3;
  }
  if(fread((char *)&InfoHead,1,sizeof(BITMAPINFOHEADER),fp) !=
     sizeof(BITMAPINFOHEADER))
  {
    fclose(fp);
    return -4;
  }
  if(InfoHead.biCompress != 0)
  {
    fclose(fp);
    return -5;
  }
  if(InfoHead.biBitCount != 1 && InfoHead.biBitCount != 4 &&
     InfoHead.biBitCount != 8)
  {
    fclose(fp);
    return -6;
  }
  if(InfoHead.biWidth > 4096)
  {
    fclose(fp);
    return -7;
  }

  gn_pic_w = (USGI)InfoHead.biWidth;
  gn_pic_h = (USGI)InfoHead.biHeight;
  gn_pic_lb = gn_pic_w / (8 / InfoHead.biBitCount);
  gn_line_bytes = ((gn_pic_lb + 3) / 4) * 4;
  /* .BMP 文件每行是凑满 4 字节倍数的 */
  gn_bit_pp = InfoHead.biBitCount;           /* 每个像素占用位数 */
  gn_pix_pb = 8 / gn_bit_pp;                 /* 每个字节像素个数 */
  gc_base = 0xFF << (8 - gn_bit_pp);         /* 运算基 */

  if((1 << InfoHead.biBitCount) > gn_vid_color_num) /* 屏幕颜色数比文件小 */
  {
    fclose(fp);
    return 0;
  }

  if(gl_index_color == NO)  /* first file */
    gn_color_num = 1 << InfoHead.biBitCount;
  else
    color2 = 1 << InfoHead.biBitCount;

  gn_win_left = min(max(wx0, 0), gn_MAX_X_RES - 1);
  gn_win_top = min(max(wy0, 0), gn_MAX_Y_RES - 1);
  if(wx <= 0) gn_win_w = gn_pic_w;
  else        gn_win_w = wx;
  gn_win_w = min(gn_win_w, gn_MAX_X_RES - gn_win_left);
  if(wy <= 0) gn_win_h = gn_pic_h;
  else        gn_win_h = wy;
  gn_win_h = min(gn_win_h, gn_MAX_Y_RES - gn_win_top);

  if(gl_set_palette == NO)
  {
    read_palette(fp, ga_palette, gn_color_num);
    calc_pal_gray(ga_palette, ga_gray);
  }
  else
  {
    read_palette(fp, pal2, color2);
    calc_pal_gray(pal2, gray2);
    for(j = 0; j < color2; j++)
    {
      pre_gray_val = 300.0;
      for(i = 0; i < gn_color_num; i++)
      {
        gray_val = gray2[j] - ga_gray[i];
        if(gray_val < 0.0) gray_val = -gray_val;
        if(gray_val < pre_gray_val)
        {
          pre_gray_val = gray_val;
          k = i;
        }
      }
      c_index[j] = k;
    }
    for(i = 0; i < gn_color_num; i++)
    {
      k = 1;
      rr = ga_palette[i][0];
      gg = ga_palette[i][1];
      bb = ga_palette[i][2];
      for(j = 0; j < color2; j++)
      {
        if(i == c_index[j])
        {
          k++;
          rr += pal2[j][0];
          gg += pal2[j][1];
          bb += pal2[j][2];
        }
      }
      ga_palette[i][0] = rr/k;
      ga_palette[i][1] = gg/k;
      ga_palette[i][2] = bb/k;
    }
    gl_set_palette = NO;
  }

  VGA_set_palette((USGC *)ga_palette, gn_color_num);
  while(1)
  {
    if(show_bmp(fp, c_index) != 0)
    {
      fclose(fp);
      return -8;
    }
    if(gl_browse_bmp != 1) break;
    if(browse_pic_read_key() == KEY_ESC) break;
  }
  gl_index_color = YES;  /* first file finished */
  fclose(fp);
  return 0;
}

/* ------------------------------------------------------------------------- */
char *bmp_info(char *filename, char *info_str)
/*
   将 .BMP 文件 filename 的信息输出到字符串 info_str 中并返回
*/
{
  sprintf(info_str, "%s %dx%d(%d)", filename, gn_pic_w, gn_pic_h,
          1 << InfoHead.biBitCount);
  return info_str;
}

/* ------------------------------------------------------------------------- */
int  main(int argc, char **argv)
{
  int  mode = 0x5D, wx0 = 0, wy0 = 0, wx = 0, wy = 0;
  int  rc = 0;    /* function return code */
  USGC cls_color = 0x0F;
  int  func;
  struct ffblk ffblk;
  int  done;
  int  m = 0;
  char info_str[256];

  if(argc < 3)
  {
    printf("/nShow .BMP files images for SVGA 640*480(256/16 colors) mode/n");
    printf("(C) M.L.Y  2000.9, 2000.12/n/n");
    printf("Usage: %s 1 bmpfile win_left win_top win_w win_h color/n",
           strupr(argv[0]));
    printf("   or: %s 2 *.BMP color/n", strupr(argv[0]));
    printf("where: color = 16 or 256(default)/n");
    printf("/ne.g.: %s 1 LOGO256.BMP 0 0 300 200 256/n", strupr(argv[0]));
    return 1;
  }
  func = atoi(argv[1]);
  if(func == 1)
  {
    if(argc >= 4) wx0 = atoi(argv[3]);
    if(argc >= 5) wy0 = atoi(argv[4]);
    if(argc >= 6) wx = atoi(argv[5]);
    if(argc >= 7) wy = atoi(argv[6]);
    if(argc >= 8)
      if(atoi(argv[7]) == 16) mode = 0x12;
    gl_browse_bmp = YES;         /* can browse the image */
  }
  else
  {
    if(argc >= 4)
      if(atoi(argv[3]) == 16) mode = 0x12;
    gl_browse_bmp = NO;
  }

  set_mode(mode);
  if(func == 1)
    rc = show_bmp_img(argv[2], wy0, wx0, wy, wx);
  else
  {
    SVGA_cls(cls_color);
    done = findfirst(argv[2], &ffblk, 0);
    while (!done)
    {
      func = 0;
      rc = show_bmp_img(ffblk.ff_name, m/2*240+6, m%2*320+6, 200, 300);
      if(rc == 0)
      {
        SVGA_disp8x8ascstr(bmp_info(ffblk.ff_name, info_str),
                           m/2*240+210, m%2*320+10, m+0xa, IMG_XOR_PUT);
        m++;
      }
      if(m >= 2*2)
      {
        m = 0;
        func = getch();
        SVGA_cls(cls_color);
      }
      done = findnext(&ffblk);
    }
    if(func == 0) getch();  /* wait press any key to exit */
  }
  set_mode(3);
  if(rc != 0) printf("/nError: return code = %d/n", rc);
  return 0;
}

/* End of file */

 
原创粉丝点击