/***********************************************************/
/* bitmap データ ダンププログラム    2010.5.30             */
/*                                                         */
/* 4, 8, 24, 32 bit Bitmap に対応                          */
/* 出力データ                                              */
/* R(赤)値 G(緑)値 B(青)値                                 */
/*                                                         */
/* kondo@kk.iij4u.or.jp      2000.08.03                    */
/* 1 bit Bitmap に対応させた 2010.5.5  Y. Fukui            */
/***********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void usage(char *cmdname)
{
  fprintf(stderr,
          "\n"
          "ビットマップファイル ---> テキストダンプ プログラム\n"
          "Usage : %s bmp_file [text_file]\n"
          "  bmp_file  : ビットマップファイル\n"
          "              (無圧縮 4, 8, 24, 32bit のみ対応)\n"
          "  text_file : 指定しない場合 \"bmp_file.txt\" が出力されます\n"
          "\n"
          "  出力形式 : 各色 0~255\n"
          "\tRed Green Blue\n"
          "\tRed Green Blue\n"
          "\t :    :    :\n"
          "\n"
          "  画像のサイズによってダンプファイルがかなり大きくなるので\n"
          "  注意してください\n" "\n", cmdname);
  exit(1);
}

/*----------------*/
/* ファイル名取得 */
/*----------------*/
int getbasename(char *dest, char *src)
{
  int i, start, end, ret;

  i = -1;
  start = 0;
  end = 0;

  // ファイル名のはじめと終わりを検出
  while (src[++i]) {
    if (src[i] == '\\' || src[i] == ':') {
      start = i + 1;
      end = 0;
    }
    if (src[i] == '.') {
      end = i;
    }
  }
  if (end == 0) {
    end = i;
  }
  // ファイル名が有る場合
  if (start < end) {
    for (i = 0; i < end; i++) {
      dest[i] = src[i];
    }
    dest[i] = '\0';
    ret = 1;
  }
  else {
    dest[0] = '\0';
    ret = 0;
  }

  return ret;
}

/*----------------------------*/
/* ファイルヘッダ部 (14 Byte) */
/*----------------------------*/
int fileheader(FILE * fp, long *offset)
{
  int count = 0;
  long var_long;
  short var_short;
  char s[10];

  // BITMAP 認識文字 "BM"
  if (fread(s, 2, 1, fp) == 1) {
    if (memcmp(s, "BM", 2) == 0) {
      printf("[BM] BITMAP file\n");
    }
    else {
      fprintf(stderr, "%s : Not a BITMAP file\n", s);
      exit(1);
    }
    count += 2;
  }
  printf("  [BITMAPFILEHEADER]\n");
  // ファイルサイズ
  if (fread(&var_long, 4, 1, fp) == 1) {
    printf("  Size          : %ld [Byte]\n", var_long);
    count += 4;
  }
  // 予約領域 0
  if (fread(&var_short, 2, 1, fp) == 1) {
    count += 2;
  }
  // 予約領域 0
  if (fread(&var_short, 2, 1, fp) == 1) {
    count += 2;
  }
  // ファイルの先頭から画像データまでの位置
  if (fread(&var_long, 4, 1, fp) == 1) {
    printf("  OffSets       : %ld [Byte]\n", var_long);
    *offset = var_long;
    count += 4;
  }
  return count;
}

/*------------------------------------------------------------------*/
/* 情報ヘッダ部 (12 Byte -> OS/2 Bitmap, 40 Byte -> Windows Bitmap) */
/*------------------------------------------------------------------*/
int infoheader(FILE * fp,
               short *infosize,
               long *width, long *height,
               long *x_coodinate, long *y_coodinate,
               short *BitCount,
               long *ClrUsed)
{
  int count = 0;
  long var_long, compress = 0;
  short var_short;

  // BITMAPINFOHEADER のサイズ
  if (fread(&var_long, 4, 1, fp) == 1) {
    count += 4;
    *infosize = var_long;
  }

  printf("  [BITMAPINFOHEADER]\n");
  // OS/2 Bitmap
  if (*infosize == 12) {
    // 画像データの幅
    if (fread(&var_short, 2, 1, fp) == 1) {
      printf("  Width         : %d [pixel]\n", var_short);
      *width = var_short;
      count += 2;
    }
    // 画像データの高さ
    if (fread(&var_short, 2, 1, fp) == 1) {
      printf("  Height        : %d [pixel]\n", var_short);
      *height = var_short;
      count += 2;
    }
    // プレーン数 (1のみ)
    if (fread(&var_short, 2, 1, fp) == 1) {
      count += 2;
    }
    // 1画素あたりのビット数 (1, 4, 8, 24, 32)
    if (fread(&var_short, 2, 1, fp) == 1) {
      printf("  BitCount      : %d [bit]\n", var_short);
      *BitCount = var_short;
      count += 2;
    }
  }
  // Windows BMP
  else if (*infosize == 40) {
    // 画像データの幅
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  Width         : %ld [pixel]\n", var_long);
      *width = var_long;
      count += 4;
    }
    // 画像データの高さ
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  Height        : %ld [pixel]\n", var_long);
      *height = var_long;
      count += 4;
    }
    // プレーン数 (1のみ)
    if (fread(&var_short, 2, 1, fp) == 1) {
      count += 2;
    }
    // 1画素あたりのビット数 (1, 4, 8, 24, 32)
    if (fread(&var_short, 2, 1, fp) == 1) {
      printf("  BitCount      : %d [bit]\n", var_short);
      *BitCount = var_short;
      count += 2;
    }
    // 圧縮方式  0 : 無圧縮
    //           1 : BI_RLE8 8bit RunLength 圧縮
    //           2 : BI_RLE4 4bit RunLength 圧縮
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  Compression   : %ld\n", var_long);
      compress = var_long;
      count += 4;
    }
    // 画像データのサイズ
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  SizeImage     : %ld [Byte]\n", var_long);
      count += 4;
    }
    // 横方向解像度 (Pixel/meter)
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  XPelsPerMeter : %ld [pixel/m]\n", var_long);
      *x_coodinate = var_long;
      count += 4;
    }
    // 縦方向解像度 (Pixel/meter)
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  YPelsPerMeter : %ld [pixel/m]\n", var_long);
      *y_coodinate = var_long;
      count += 4;
    }
    // 使用色数
    if (fread(&var_long, 4, 1, fp) == 1) {
      printf("  ClrUsed       : %ld [color]\n", var_long);
      *ClrUsed = var_long;
      count += 4;
    }
    // 重要な色の数 0の場合すべての色
    if (fread(&var_long, 4, 1, fp) == 1) {
      count += 4;
    }
  }
  else {
    fprintf(stderr, "Bitmap Info Header error\n");
  }

  if (compress != 0) {
    fprintf(stderr, "圧縮ビットマップには対応していません\n");
    exit(1);
  }

  if (*BitCount == 1 || *BitCount == 4 || *BitCount == 8 || *BitCount == 24 || *BitCount == 32) {
    ;
  }
  else {
    fprintf(stderr, "本プログラムは、%d ビット色には対応していません\n", *BitCount);
    exit(1);
  }
  return count;
}

/*------------------*/
/* 使用色数カウント */
/*------------------*/
long usedcolor(short bits, long color)
{
  if (color != 0) {
    return color;
  }
  else {
    return 1 << bits;
  }
}

/*-------------*/
/* OS/2 bitmap */
/*-------------*/
int rgbtriple(FILE * fp,
              long used,
              unsigned char *red,
              unsigned char *green,
              unsigned char *blue)
{
  long i;
  int count = 0;

  // ビットの並びは B G R
  for (i = 0; i < used; i++) {
    blue[i] = fgetc(fp);
    green[i] = fgetc(fp);
    red[i] = fgetc(fp);
    count++;
  }

  return count;
}

/*----------------*/
/* Windows bitmap */
/*----------------*/
int rgbquad(FILE * fp,
            long used,
            unsigned char *red,
            unsigned char *green,
            unsigned char *blue)
{
  long i;
  int receive, count = 0;

  // ビットの並びは B G R 予約
  for (i = 0; i < used; i++) {
    blue[i] = fgetc(fp);
    green[i] = fgetc(fp);
    red[i] = fgetc(fp);
    receive = fgetc(fp);
    count++;
  }
  return count;
}

/*----------------*/
/* テキストダンプ */
/*----------------*/
long dump32(FILE * bmp,
            FILE * txt,
            long offset,
            long width,
            long height,
            short bits,
            unsigned char *red,
            unsigned char *green,
            unsigned char *blue)
{
  int r, g, b, alpha;
  long i, j, line, position, count = 0;

//  fprintf(txt,"%d\t%d\t%d\n",width,height,bits);
  // 4byte 境界にあわせる
  line = (width * bits) / 8;
  if ((line % 4) != 0) {
    line = ((line / 4) + 1) * 4;
  }

  for (i = 0; i < height; i++) {
    // 行の先頭位置
    position = offset + line * (height - (i + 1));
    fseek(bmp, position, SEEK_SET);

    // 値の読み込み
    for (j = 0; j < width; j++) {
      // 32 bit 色
      if (bits == 32) {
        b = fgetc(bmp);
        g = fgetc(bmp);
        r = fgetc(bmp);
        alpha = fgetc(bmp);
        fprintf(txt, "%d\t%d\t%d\n", r, g, b);
        count++;
      }
      // 24 bit 色
      else if (bits == 24) {
        b = fgetc(bmp);
        g = fgetc(bmp);
        r = fgetc(bmp);
        fprintf(txt, "%d\t%d\t%d\n", r, g, b);
        count++;
      }
      // 8 bit 色
      else if (bits == 8) {
        int index;

        index = fgetc(bmp);
        fprintf(txt, "%d\t%d\t%d\n", red[index], green[index], blue[index]);
        count++;
      }
    }
    fprintf(txt, "\n");
  }
  return count;
}

long dump4(FILE * bmp,
           FILE * txt,
           long offset,
           long width,
           long height,
           short bits,
           unsigned char *red,
           unsigned char *green,
           unsigned char *blue)
{
  long i, j, k, line, position, count = 0;
  int index, high, low;

//  fprintf(txt,"%d\t%d\t%d\n",width,height,bits);
  // 4byte 境界にあわせる
  line = (width * bits) / 8;
  if ((line % 4) != 0) {
    line = ((line / 4) + 1) * 4;
  }
  k = (int) ((double) width / 2.0 + 0.5);

  for (i = 0; i < height; i++) {
    // 行の先頭位置
    position = offset + line * (height - (i + 1));
    fseek(bmp, position, SEEK_SET);
    count = 0;
    // 値の読み込み
    for (j = 0; j < k; j++) {
      index = fgetc(bmp);
      // 上位 4bit
      high = index >> 4;
      // 下位 4bit
      low = index & 15;
      fprintf(txt, "%d\t%d\t%d\n",
               red[high], green[high], blue[high]);
      count++;
      if( count >= width )break;
      fprintf(txt, "%d\t%d\t%d\n",
               red[high], green[high], blue[high]);
      count++;
    }
    fprintf(txt, "\n");
  }
  return count;
}

long dump1(FILE * bmp,
           FILE * txt,
           long offset,
           long width,
           long height,
           short bits,
           unsigned char *red,
           unsigned char *green,
           unsigned char *blue)
{
  long i, j, k, line, position, count = 0;
  int bytecount, pattern, index, hcount;

//  fprintf(txt,"%d\t%d\t%d\n",width,height,bits);
  // 4byte 境界にあわせる
  line = (width * bits) / 8;
  if ((line % 4) != 0) {
    line = ((line / 4) + 1) * 4;
  }
  for (i = 0; i < height; i++) {
    // 行の先頭位置
    position = offset + line * (height - (i + 1));
    fseek(bmp, position, SEEK_SET);
    // 値の読み込み
    bytecount = (width - 1)/4 + 1;
    hcount = 0; // x方向1行の中でのカウント

    for (j = 0; j < bytecount; j++) {
      k = 0;
      pattern = fgetc(bmp);
      while( k < 8 && hcount < width ){
        index = (pattern >>(7 - k)) & 1;  // パレットの番号
        fprintf(txt, "%d\t%d\t%d\t\n",red[index],green[index],blue[index]);
        hcount ++; k++;
      }
      count += 2;
    }

    fprintf(txt, "\n");
  }
  return count;
}

/*------------*/
/* ダンプ処理 */
/*------------*/
void dumpprocess(char *bmpfile, char *textfile)
{
  short infosize, bits;
  long used = 0, color = 0, offset, width, height, xreso, yreso;
  unsigned char red[256], green[256], blue[256];
  FILE *fp1, *fp2;

  if ((fp1 = fopen(bmpfile, "rb")) == NULL) {
    fprintf(stderr, "Cannot open file : %s\n", bmpfile);
    exit(1);
  }
  // ヘッダ情報 BITMAPFILEHEADER
  fileheader(fp1, &offset);
  // ヘッダ情報 BITMAPINFOHEADER
  infoheader(fp1, &infosize, &width, &height, &xreso, &yreso, &bits, &color);
  color = usedcolor(bits, color);

  // OS/2 Bitmap
  if (infosize == 12) {
    if (bits == 1 || bits == 4 || bits == 8) {
      used = rgbtriple(fp1, color, red, green, blue);
    }
    printf("[OS/2 bitmap] --- %d bit %ld color\n", bits, used);
  }
  // Windows Bitmap
  else if (infosize == 40) {
    if (bits == 1 || bits == 4 || bits == 8) {
      used = rgbquad(fp1, color, red, green, blue);
    }
    printf("[Windows bitmap] --- %d bit %ld color\n", bits, used);
  }
  else if (infosize == 108) {
    printf("[other bitmap]\n");
  }
  else {
    fprintf(stderr, "BITMAP INFOHEADER error\n");
  }

  if ((fp2 = fopen(textfile, "w")) == NULL) {
    fprintf(stderr, "Cannot open file : %s\n", textfile);
    exit(1);
  }

  // テキスト出力
  if (bits == 32 || bits == 24 || bits == 8) {
    printf("%ld [pixels]\n",
           dump32(fp1, fp2, offset, width, height, bits, red, green, blue));
  }
  else if (bits == 4) {
    printf("%ld [pixels]\n",
           dump4(fp1, fp2, offset, width, height, bits, red, green, blue));
  }
  else if (bits == 1) {
    printf("%ld [pixels]\n",
           dump1(fp1, fp2, offset, width, height, bits, red, green, blue));
  }
  else {
    fprintf(stderr, "%d bit 色には対応していません\n", bits);
    exit(1);
  }

  fclose(fp1);
  fclose(fp2);
}

/**************/
/* メイン関数 */
/**************/
int main(int argc, char *argv[])
{
  char txtfile[255], bmpfile[255];

  if (argc < 2) {
    usage(argv[0]);
  }
  else if (argc == 2) {
    char basename[255];

    strcpy(bmpfile, argv[1]);
    getbasename(basename, argv[1]);
    sprintf(txtfile, "%s.txt", basename);
  }
  else if (argc == 3) {
    strcpy(bmpfile, argv[1]);
    strcpy(txtfile, argv[2]);
  }
  else {
    usage(argv[0]);
  }

  dumpprocess(bmpfile, txtfile);

  return 0;
}
最終更新:2010年05月30日 21:29