FC2カウンター FPGAの部屋 VC++

FPGAやCPLDの話題やFPGA用のツールの話題などです。 マニアックです。 日記も書きます。

FPGAの部屋

FPGAの部屋の有用と思われるコンテンツのまとめサイトを作りました。Xilinx ISEの初心者の方には、FPGAリテラシーおよびチュートリアルのページをお勧めいたします。

Visual Studio 2008でのコンソールCアプリケーション

久しぶりにVC++でコードを書いたら、いつの間にか、mainが_tmainになって、char* argv[]が_TCHAR* argv[]になっていた。
argv[1]をsscanf(argv[1], "%d", &a)でint aに値を取り込もうと思ってもエラーになってしまう。(プロパティで変えられると思うけど。。。)
この最、勉強して、Unicodeで書いてみた。コードはBMPのRGBコードの指定された何ビットかを落とすソフトウェアだ。

sscanf(argv[1], "%d",&bit_and);



_stscanf_s(argv[1], _T("%d"), &bit_and, sizeof(int));


に書き換えた。
下にすべてのソースコードを示す。

// Data2BitLimit.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//
// 使い方:Data2BitLimit <落とすビット数> <元のBMPファイル名> <ビット数を落としたBMPファイル名>
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <cstring>

#include "stdafx.h"

int _tmain(int argc, _TCHAR* argv[])
{
    _TCHAR org_file[100];
    _TCHAR new_file[100];
    BITMAPFILEHEADER bmpfh; // BMPファイルのファイルヘッダ
    BITMAPINFOHEADER bmpih; // BMPファイルのINFOヘッダ
    FILE *orgfp, *newfp;
    BMP24FORMAT **bmp_data; // 24ビットのBMPファイルのデータ 640*480
    int i, j;
    int bit_and;
    unsigned char bit_and_pt;

    // 引数の処理
    if (argc==1){ // 引数なしはエラー
        fprintf(stderr, "使い方:Data2BitLimit <落とすビット数> <元のBMPファイル名(cam_bmp_file.bmp)> <ビット数を落としたBMPファイル名(new_bmp_file.bmp)>\n");
        exit(1);
        //bit_and = 2;
        //_stprintf_s(org_file, 100, _T("cam_bmp_file.bmp"), 138);
        //_stprintf_s(new_file, 100, _T("new_bmp_file.bmp"), 138);
    } else if (argc==2) { // 引数1つ、落とすビット数
        _stscanf_s(argv[1], _T("%d"), &bit_and, sizeof(int));
        _stprintf_s(org_file, 100, _T("cam_bmp_file.bmp"), 138);
        _stprintf_s(new_file, 100, _T("new_bmp_file.bmp"), 138);
    } else if (argc==3) {
        _stscanf_s(argv[1], _T("%d"), &bit_and, sizeof(int));
        _stprintf_s(org_file, 100, argv[2]);
        _stprintf_s(new_file, 100, _T("new_bmp_file.bmp"), 138);
    } else { // それ以外
        _stscanf_s(argv[1], _T("%d"), &bit_and, sizeof(int));
        _stprintf_s(org_file, 100, argv[2]);
        _stprintf_s(new_file, 100, argv[3]);
    }

    
    if (_tfopen_s(&orgfp, org_file, _T("rb")) != 0) { // org_fileをバイナリリードモードでオープン
        fprintf(stderr, "Can't Open %s\n", org_file);
        exit(1);
    }
    if (_tfopen_s(&newfp, new_file, _T("wb")) != 0) { // new_fileをバイナリライトモードでオープン
        fprintf(stderr, "Can't Open %s\n", new_file);
        exit(1);
    }
    
    // BMPファイルヘッダの読み出し
    fread(&bmpfh.bfType, sizeof(short), 1, orgfp);
    fread(&bmpfh.bfSize, sizeof(long), 1, orgfp);
    fread(&bmpfh.bfReserved1, sizeof(short), 1, orgfp);
    fread(&bmpfh.bfReserved2, sizeof(short), 1, orgfp);
    fread(&bmpfh.bfOffBits, sizeof(long), 1, orgfp);

    fread(&bmpih.biSize, sizeof(long), 1, orgfp);
    fread(&bmpih.biWidth, sizeof(long), 1, orgfp);
    fread(&bmpih.biHeight, sizeof(long), 1, orgfp);
    fread(&bmpih.biPlanes, sizeof(unsigned short), 1, orgfp);
    fread(&bmpih.biBitCount, sizeof(unsigned short), 1, orgfp);
    fread(&bmpih.biCompression, sizeof(unsigned long), 1, orgfp);
    fread(&bmpih.biSizeImage, sizeof(unsigned long), 1, orgfp);
    fread(&bmpih.biXPixPerMeter, sizeof(long), 1, orgfp);
    fread(&bmpih.biYPixPerMeter, sizeof(long), 1, orgfp);
    fread(&bmpih.biClrUsed, sizeof(unsigned long), 1, orgfp);
    fread(&bmpih.biClrImporant, sizeof(unsigned long), 1, orgfp);

    // BMPファイルヘッダの書き込み
    fwrite(&bmpfh.bfType, sizeof(short), 1, newfp);
    fwrite(&bmpfh.bfSize, sizeof(long), 1, newfp);
    fwrite(&bmpfh.bfReserved1, sizeof(short), 1, newfp);
    fwrite(&bmpfh.bfReserved2, sizeof(short), 1, newfp);
    fwrite(&bmpfh.bfOffBits, sizeof(long), 1, newfp);

    fwrite(&bmpih.biSize, sizeof(long), 1, newfp);
    fwrite(&bmpih.biWidth, sizeof(long), 1, newfp);
    fwrite(&bmpih.biHeight, sizeof(long), 1, newfp);
    fwrite(&bmpih.biPlanes, sizeof(unsigned short), 1, newfp);
    fwrite(&bmpih.biBitCount, sizeof(unsigned short), 1, newfp);
    fwrite(&bmpih.biCompression, sizeof(unsigned long), 1, newfp);
    fwrite(&bmpih.biSizeImage, sizeof(unsigned long), 1, newfp);
    fwrite(&bmpih.biXPixPerMeter, sizeof(long), 1, newfp);
    fwrite(&bmpih.biYPixPerMeter, sizeof(long), 1, newfp);
    fwrite(&bmpih.biClrUsed, sizeof(unsigned long), 1, newfp);
    fwrite(&bmpih.biClrImporant, sizeof(unsigned long), 1, newfp);

    // メモリをアロケートする
    if ((bmp_data=(BMP24FORMAT **)malloc(sizeof(BMP24FORMAT *)*bmpih.biHeight)) == NULL){
        fprintf(stderr, "bmp_dataの1次元目の480ののメモリを確保できません\n");
        exit(1);
    }
    for (i=0; i<bmpih.biHeight; i++){
        if ((bmp_data[i]=(BMP24FORMAT *)malloc(sizeof(BMP24FORMAT) * bmpih.biWidth)) == NULL){
            fprintf(stderr, "bmp_dataの2次元目の%d番目のメモリが確保できません\n");
            exit(1);
        }
    }

    // ビットを落として書き込む
    for (i=0, bit_and_pt=0; i<bit_and; i++)
        bit_and_pt = bit_and_pt | (1<<i);
    bit_and_pt = 0xff ^ bit_and_pt;

    for (i=0; i<bmpih.biHeight; i+=1){
        for (j=0; j<bmpih.biWidth; j+=1){
            bmp_data[i][j].blue = fgetc(orgfp);
            bmp_data[i][j].green = fgetc(orgfp);
            bmp_data[i][j].red = fgetc(orgfp);
            
            fputc((int)(bmp_data[i][j].blue & bit_and_pt), newfp);
            fputc((int)(bmp_data[i][j].green & bit_and_pt), newfp);
            fputc((int)(bmp_data[i][j].red & bit_and_pt), newfp);
        }
    }

    fclose(orgfp);
    fclose(newfp);
    
    for (i=0; i<bmpih.biHeight; i++)
        free(bmp_data[i]);
    free(bmp_data);
    return 0;
}


ヘッダは、ここにある
最初に、BMPヘッダの読み出しで、下のコードで良いと思った。

fread(&bmpfh, sizeof(BITMAPFILEHEADER), 1, orgfp);
fread(&bmpih, sizeof(BITMAPINFOHEADER), 1, orgfp);


上のコードを使用したところ、構造体tagBITMAPFILEHEADERは、最初にshort bfTypeがあって、次がlong bfSizeだったが、bfSizeの値が違っていた。おかしいと思ったら、どうやら、short bfSize、2バイトの後に、2バイトのダミー・パッディングが入っていて、その後にlong bfSizeだと、状況があう。どうやら、4バイト境界に構造体のメンバを揃えているようだ。(少なくともintやlongは)というわけで、構造体を一気にファイルから読むという目論見は甘いという教訓を得た。
改めて考えてみると、4バイト境界に揃っていたほうが1サイクルで読めるし、効率が良いと思う。

#fprintfがそのまま使ってあるから、後で直すことにする。
fprintfを_ftprintf_sに変更して、文字列は、_T( )でくくりました。

参考にしたWebサイト”Visual C++のUNICODE対応”、”VC++2005よりセキュリティが強化された関数の一覧"
  1. 2010年10月13日 21:16 |
  2. VC++
  3. | トラックバック:0
  4. | コメント:4