1200392959 画像の作成についての質問です。添付させていただいた画像は128×128pixelの画像でペイントでキャンバスのサイズを指定した後にテキストでABC(フォントは14でTime new roman)と書いた後に色の反転をした画像です。例えばこれをAAA~ZZZまで変化させて26の3乗個の画像を作り出す、もしくは手に入れるにはどのようにするのが効率良いのでしょうか?アイデアがある方はよろしくお願い申し上げます。フォントなどは気にしていませんので、アルファベットが並んだ画像を手に入れるのが目的です。真に申し訳ないのですが当方マクロなどの知識がなく、できれば簡単にできる方法を教えていただけると助かります。プログラミングに関してはC言語でしたら一通り使えると思います。どうかよろしくお願いいたします。

回答の条件
  • 1人3回まで
  • 登録:2008/01/15 19:29:21
  • 終了:2008/01/19 12:57:59

ベストアンサー

id:Mook No.2

Mook回答回数1312ベストアンサー獲得回数3912008/01/15 20:50:47

ポイント150pt

下記に参考になるサイトがありました。

http://codezine.jp/a/article/aid/1643.aspx?p=2


フォントのサイズ(pt)は画像解像度が決まらないとピクセルへの変換ができないので、今回は128ピクセルに対して、全体が収まるサイズを優先しました。


上に紹介されたページに掲載されたコードを変更しただけですが、下記のコードで一応質問された内容の結果になるかと思います。

下記はA~Cの範囲で作成するようになっているので、CをZにすれば 26^3 の画像を生成します。


(一応 Borland のコンパイラで動作確認済みです。)

#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<string.h>

#define     IMAGE_SIZE  128
#define     FONT_SIZE   48


//BITMAPINFO構造体を再定義
//モノラルビットマップなので、RGBQUAD構造体配列の長さは2
typedef struct tagMYBITMAPINFO{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[2]; 
}MYBITMAPINFO;


//RGBQUAD構造体配列
int Colors[2] = {
    0x00000000, //黒
    0x00FFFFFF, //白
};

//画像データのサイズを取得する関数
//4バイト(32ビット)区切りになるようにする
//4バイト(32ビット)のブロックがいくつになるか計算して、
//4と高さを掛ける
int GetSizeImage(int size){
    return ((size- 1) / 32 + 1) * 4 * size;
}

//フォント作成用関数
HFONT CreateMyFont(unsigned char *FontName,int FontSize){
    LOGFONT lf;
    ZeroMemory(&lf,sizeof(LOGFONT));
    lf.lfHeight = FontSize;
    lf.lfWidth = 0;
    lf.lfEscapement = 0;
    lf.lfOrientation = 0;
    lf.lfWeight = 0;
    lf.lfItalic = 0;
    lf.lfUnderline = 0;
    lf.lfStrikeOut = 0;
    lf.lfCharSet = DEFAULT_CHARSET;
    lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf.lfQuality = DEFAULT_QUALITY;
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    lstrcpy(lf.lfFaceName,FontName);
    return CreateFontIndirect(&lf);
}

//文字描画関数
//Unicode(UTF-16)をいったん文字列に変換してから
//TextOutWで文字を出力する
void DrawChar(HDC hdc,wchar_t *ws,int FontSize){
    SIZE size;
    //半角文字を考慮して中央に描画する
    GetTextExtentPoint32W(hdc, ws, lstrlenW(ws),&size);
    TextOutW(hdc,(FontSize - size.cx) / 2, ( IMAGE_SIZE - FONT_SIZE ) / 2  ,ws,lstrlenW(ws));
}

//BITMAPFILEHEADER構造体をセットする関数
void SetBitmapFileHeader(BITMAPFILEHEADER *lpbmpfh,int SizeImage){
    int OffBits;//画像データまでのオフセット

    OffBits = sizeof(BITMAPFILEHEADER) 
            + sizeof(BITMAPINFOHEADER) 
            + sizeof(Colors);

    ZeroMemory(lpbmpfh,sizeof(BITMAPFILEHEADER));
    lpbmpfh->bfType = 0x4D42; //BM
    lpbmpfh->bfSize = OffBits + SizeImage;
    lpbmpfh->bfOffBits = OffBits;
}
//BITMAPINFOHEADER構造体をセットする関数
void SetBitmapInfoHeader(BITMAPINFOHEADER *lpbmpih,
                         int SizeImage,
                         int FontSize){
    ZeroMemory(lpbmpih,sizeof(BITMAPINFOHEADER));
    lpbmpih->biSize = 40;
    lpbmpih->biWidth = FontSize;    //画像の幅・高さはFontSizeにする
    lpbmpih->biHeight = FontSize;
    lpbmpih->biPlanes = 1;
    lpbmpih->biBitCount = 1;        //モノクロビットマップの場合は1
    lpbmpih->biSizeImage = SizeImage;
}

//lpvBitsへ画像データを読み込む関数
void SetBitmapData(void *lpvBits,
                   BITMAPINFOHEADER *lpbmpih,
                   wchar_t  *st,
                   unsigned char *FontName ) {
    HDC hdcScreen,hdc;
    HBITMAP hBitmap,hBitmapOld;
    HFONT hFont,hFontOld;
    RECT rect;
    MYBITMAPINFO mybmpi;

    hdcScreen = GetDC(NULL);  //スクリーンのデバイスコンテキストを取得
    hdc = CreateCompatibleDC(hdcScreen); //スクリーン互換の
                                         //デバイスコンテキストを取得

    hBitmap = CreateCompatibleBitmap(hdcScreen,IMAGE_SIZE,IMAGE_SIZE);
                                 //スクリーン互換のビットマップを作成

    hBitmapOld = SelectObject(hdc,hBitmap);

    hFont = CreateMyFont(FontName,FONT_SIZE);//フォントを作成
    hFontOld = SelectObject(hdc,hFont);

    //半角文字を考慮して、背景を白で埋めておく
    SetRect(&rect,0,0,IMAGE_SIZE, IMAGE_SIZE);
    FillRect(hdc,&rect,GetStockObject(WHITE_BRUSH));

    DrawChar(hdc,st,IMAGE_SIZE);//文字を描画

    //MYBITMAPINFO構造体をセット
    mybmpi.bmiHeader = *lpbmpih;
    memcpy(mybmpi.bmiColors,Colors,sizeof(Colors));

    //lpvBitsへビットマップデータを読み込む
    GetDIBits(hdc,hBitmap,0,IMAGE_SIZE,
              lpvBits,(BITMAPINFO *)&mybmpi,DIB_RGB_COLORS);

    //以下、終了処理
    DeleteObject(SelectObject(hdc,hBitmapOld));
    DeleteObject(SelectObject(hdc,hFontOld));

    DeleteDC(hdc);
    ReleaseDC(NULL,hdcScreen);
}

void CharCodeToBitmapFile(wchar_t *CharCode,
                          unsigned char *FontName,
                          unsigned char *FileName){
    int SizeImage;
    BITMAPFILEHEADER bmpfh;
    BITMAPINFOHEADER bmpih;
    void *lpvBits;
    FILE *fp;

    //画像データのサイズを取得
    SizeImage = GetSizeImage(IMAGE_SIZE); 

    //BITMAPFILEHEADER構造体をセット
    SetBitmapFileHeader(&bmpfh,IMAGE_SIZE);

    //BITMAPINFOHEADER構造体をセット
    SetBitmapInfoHeader(&bmpih,SizeImage,IMAGE_SIZE);

    //バッファを用意
    lpvBits = (void *)malloc(SizeImage);

    //画像データを読み込む
    SetBitmapData(lpvBits,&bmpih,CharCode,FontName);

    //ファイルへの書き込み
    fp = fopen(FileName,"wb");
    fwrite(&bmpfh,sizeof(BITMAPFILEHEADER),1,fp);
    fwrite(&bmpih,sizeof(BITMAPINFOHEADER),1,fp);
    fwrite(Colors,sizeof(Colors),1,fp);
    fwrite(lpvBits,SizeImage,1,fp);
    fclose(fp);

    free(lpvBits);//バッファを解放
}

int main(void){
    wchar_t  st[4];
    wchar_t i, j, k;
    char     file_name[32];
    st[3] = '\0';

    for ( i='A' ; i <= 'C' ; i++ ) {
        st[0] = i;
        for ( j='A' ; j <= 'C' ; j++ ) {
                st[1] = j;
            for ( k='A' ; k <= 'C' ; k++ ) {
                st[2] = k;
                sprintf( file_name, ".\\%c%c%c.bmp", (char)i, (char)j, (char)k );
                printf( "make %s\n", file_name );
                CharCodeToBitmapFile( st, "Time new roman",file_name );
            }
        }
    }
    return 0;
}
id:jsakato

ご回答ありがとうございます。ご提示していただきましたプログラムを実行しましたところビットマップファイルは作成されるのですが、開く事ができませんでした。いくつかのフォトタッチソフトで開く事を試みましたが「デコードエラー」「ストリームからの読み込みエラー」などの表示が出て読み込む事ができませんでした。お手数おかけしますが当方には原因が分からないので解決策を教えていただけると助かります。

2008/01/16 02:02:10

その他の回答(1件)

id:khoshi3 No.1

khoshi3回答回数71ベストアンサー獲得回数122008/01/15 19:57:40

ポイント50pt

Gdライブラリを使うと、任意の文字列を含む画像を動的に生成できます。C言語での例は、下記URLのgdImageChar()のところを見てください。:

  • gd ライブラリの index.htm (version 1.3) のあてにならない参考のための抄訳:

http://www2d.biglobe.ne.jp/~gama/cgi/gd/gd13.htm

perl用のモジュールもあり、perlのCGIから使えます。(わたしが使ったことがあるのはこっちです。):

  • web と CGI のひみつ - 画像生成:

http://x68000.q-e-d.net/~68user/webcgi/image-1.html

プログラムを書かずに済ます方法としては、アクセスカウンタをカウンタとして利用せず、任意の文字列を"lit="で表示させるようにするという方法もあると思います。

(AからZの1文字ずつのGIFファイルは準備する必要はあると思います。ただし、ご希望通りの128x128pixelの画像ではなくなります。)

http://www.exe.ne.jp/~staff/manual/counter.html

lit=X 文字列表示 (Display literal)

表示できる文字(0123456789:ap,-)の中より、任意に指定して、 固定的に表示することができます。

id:jsakato

ご回答いただきありがとうございました。

これを機にCGIも勉強してみようと思います。またの機会がありましたら是非よろしくお願いいたします。

2008/01/19 12:56:53
id:Mook No.2

Mook回答回数1312ベストアンサー獲得回数3912008/01/15 20:50:47ここでベストアンサー

ポイント150pt

下記に参考になるサイトがありました。

http://codezine.jp/a/article/aid/1643.aspx?p=2


フォントのサイズ(pt)は画像解像度が決まらないとピクセルへの変換ができないので、今回は128ピクセルに対して、全体が収まるサイズを優先しました。


上に紹介されたページに掲載されたコードを変更しただけですが、下記のコードで一応質問された内容の結果になるかと思います。

下記はA~Cの範囲で作成するようになっているので、CをZにすれば 26^3 の画像を生成します。


(一応 Borland のコンパイラで動作確認済みです。)

#include<stdio.h>
#include<windows.h>
#include<stdlib.h>
#include<string.h>

#define     IMAGE_SIZE  128
#define     FONT_SIZE   48


//BITMAPINFO構造体を再定義
//モノラルビットマップなので、RGBQUAD構造体配列の長さは2
typedef struct tagMYBITMAPINFO{
    BITMAPINFOHEADER bmiHeader;
    RGBQUAD bmiColors[2]; 
}MYBITMAPINFO;


//RGBQUAD構造体配列
int Colors[2] = {
    0x00000000, //黒
    0x00FFFFFF, //白
};

//画像データのサイズを取得する関数
//4バイト(32ビット)区切りになるようにする
//4バイト(32ビット)のブロックがいくつになるか計算して、
//4と高さを掛ける
int GetSizeImage(int size){
    return ((size- 1) / 32 + 1) * 4 * size;
}

//フォント作成用関数
HFONT CreateMyFont(unsigned char *FontName,int FontSize){
    LOGFONT lf;
    ZeroMemory(&lf,sizeof(LOGFONT));
    lf.lfHeight = FontSize;
    lf.lfWidth = 0;
    lf.lfEscapement = 0;
    lf.lfOrientation = 0;
    lf.lfWeight = 0;
    lf.lfItalic = 0;
    lf.lfUnderline = 0;
    lf.lfStrikeOut = 0;
    lf.lfCharSet = DEFAULT_CHARSET;
    lf.lfOutPrecision = OUT_DEFAULT_PRECIS;
    lf.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    lf.lfQuality = DEFAULT_QUALITY;
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    lstrcpy(lf.lfFaceName,FontName);
    return CreateFontIndirect(&lf);
}

//文字描画関数
//Unicode(UTF-16)をいったん文字列に変換してから
//TextOutWで文字を出力する
void DrawChar(HDC hdc,wchar_t *ws,int FontSize){
    SIZE size;
    //半角文字を考慮して中央に描画する
    GetTextExtentPoint32W(hdc, ws, lstrlenW(ws),&size);
    TextOutW(hdc,(FontSize - size.cx) / 2, ( IMAGE_SIZE - FONT_SIZE ) / 2  ,ws,lstrlenW(ws));
}

//BITMAPFILEHEADER構造体をセットする関数
void SetBitmapFileHeader(BITMAPFILEHEADER *lpbmpfh,int SizeImage){
    int OffBits;//画像データまでのオフセット

    OffBits = sizeof(BITMAPFILEHEADER) 
            + sizeof(BITMAPINFOHEADER) 
            + sizeof(Colors);

    ZeroMemory(lpbmpfh,sizeof(BITMAPFILEHEADER));
    lpbmpfh->bfType = 0x4D42; //BM
    lpbmpfh->bfSize = OffBits + SizeImage;
    lpbmpfh->bfOffBits = OffBits;
}
//BITMAPINFOHEADER構造体をセットする関数
void SetBitmapInfoHeader(BITMAPINFOHEADER *lpbmpih,
                         int SizeImage,
                         int FontSize){
    ZeroMemory(lpbmpih,sizeof(BITMAPINFOHEADER));
    lpbmpih->biSize = 40;
    lpbmpih->biWidth = FontSize;    //画像の幅・高さはFontSizeにする
    lpbmpih->biHeight = FontSize;
    lpbmpih->biPlanes = 1;
    lpbmpih->biBitCount = 1;        //モノクロビットマップの場合は1
    lpbmpih->biSizeImage = SizeImage;
}

//lpvBitsへ画像データを読み込む関数
void SetBitmapData(void *lpvBits,
                   BITMAPINFOHEADER *lpbmpih,
                   wchar_t  *st,
                   unsigned char *FontName ) {
    HDC hdcScreen,hdc;
    HBITMAP hBitmap,hBitmapOld;
    HFONT hFont,hFontOld;
    RECT rect;
    MYBITMAPINFO mybmpi;

    hdcScreen = GetDC(NULL);  //スクリーンのデバイスコンテキストを取得
    hdc = CreateCompatibleDC(hdcScreen); //スクリーン互換の
                                         //デバイスコンテキストを取得

    hBitmap = CreateCompatibleBitmap(hdcScreen,IMAGE_SIZE,IMAGE_SIZE);
                                 //スクリーン互換のビットマップを作成

    hBitmapOld = SelectObject(hdc,hBitmap);

    hFont = CreateMyFont(FontName,FONT_SIZE);//フォントを作成
    hFontOld = SelectObject(hdc,hFont);

    //半角文字を考慮して、背景を白で埋めておく
    SetRect(&rect,0,0,IMAGE_SIZE, IMAGE_SIZE);
    FillRect(hdc,&rect,GetStockObject(WHITE_BRUSH));

    DrawChar(hdc,st,IMAGE_SIZE);//文字を描画

    //MYBITMAPINFO構造体をセット
    mybmpi.bmiHeader = *lpbmpih;
    memcpy(mybmpi.bmiColors,Colors,sizeof(Colors));

    //lpvBitsへビットマップデータを読み込む
    GetDIBits(hdc,hBitmap,0,IMAGE_SIZE,
              lpvBits,(BITMAPINFO *)&mybmpi,DIB_RGB_COLORS);

    //以下、終了処理
    DeleteObject(SelectObject(hdc,hBitmapOld));
    DeleteObject(SelectObject(hdc,hFontOld));

    DeleteDC(hdc);
    ReleaseDC(NULL,hdcScreen);
}

void CharCodeToBitmapFile(wchar_t *CharCode,
                          unsigned char *FontName,
                          unsigned char *FileName){
    int SizeImage;
    BITMAPFILEHEADER bmpfh;
    BITMAPINFOHEADER bmpih;
    void *lpvBits;
    FILE *fp;

    //画像データのサイズを取得
    SizeImage = GetSizeImage(IMAGE_SIZE); 

    //BITMAPFILEHEADER構造体をセット
    SetBitmapFileHeader(&bmpfh,IMAGE_SIZE);

    //BITMAPINFOHEADER構造体をセット
    SetBitmapInfoHeader(&bmpih,SizeImage,IMAGE_SIZE);

    //バッファを用意
    lpvBits = (void *)malloc(SizeImage);

    //画像データを読み込む
    SetBitmapData(lpvBits,&bmpih,CharCode,FontName);

    //ファイルへの書き込み
    fp = fopen(FileName,"wb");
    fwrite(&bmpfh,sizeof(BITMAPFILEHEADER),1,fp);
    fwrite(&bmpih,sizeof(BITMAPINFOHEADER),1,fp);
    fwrite(Colors,sizeof(Colors),1,fp);
    fwrite(lpvBits,SizeImage,1,fp);
    fclose(fp);

    free(lpvBits);//バッファを解放
}

int main(void){
    wchar_t  st[4];
    wchar_t i, j, k;
    char     file_name[32];
    st[3] = '\0';

    for ( i='A' ; i <= 'C' ; i++ ) {
        st[0] = i;
        for ( j='A' ; j <= 'C' ; j++ ) {
                st[1] = j;
            for ( k='A' ; k <= 'C' ; k++ ) {
                st[2] = k;
                sprintf( file_name, ".\\%c%c%c.bmp", (char)i, (char)j, (char)k );
                printf( "make %s\n", file_name );
                CharCodeToBitmapFile( st, "Time new roman",file_name );
            }
        }
    }
    return 0;
}
id:jsakato

ご回答ありがとうございます。ご提示していただきましたプログラムを実行しましたところビットマップファイルは作成されるのですが、開く事ができませんでした。いくつかのフォトタッチソフトで開く事を試みましたが「デコードエラー」「ストリームからの読み込みエラー」などの表示が出て読み込む事ができませんでした。お手数おかけしますが当方には原因が分からないので解決策を教えていただけると助かります。

2008/01/16 02:02:10
  • id:Mook
    そうですか。

    こちらでできたファイルは、ペイントでも画像ビューアでも見れるのですが、どのようなエラーメッセージでしょうか。

    正確な内容を教えていただけますか。
  • id:jsakato
    Mook様
    お手数おかけして申し訳ございません。
    まずペイントで開こうとしますと「メモリまたはリソースが足りないため、作業を完了できません。いくつかのプログラムを終了して、もう一度やり直してください。」と表示がされて開く事ができません。
    Windows Picture and Fax Viewerでも「プレビューを利用できません」と表示され画像を開けませんでした。

    irfan Viewで開こうとしますと「デコードエラーです。BMPは不正なファイルかサポートされていません。」と表示されて開く事ができませんでした。
  • id:Mook
    こちらでも IrfanViewで表示しましたが、問題ありませんでした。
    もしかしたら、ヘッダ情報が正しく出力されていないかもしれないですね。

    コンパイラは、何をお使いでしょうか。

    生成されたファイルをバイナリエディタで、見たときにヘッダ情報はどのようになっていますか。
    42 4D BE 00 00 00 00 00 00 00 3E 00 00 00 28 00
    00 00 80 00 00 00 80 00 00 00 01 00 01 00 00 00
    00 00 00 08 00 00 00 00 00 00 00 00 00 00 00 00
    00 00 00 00 00 00 00 00 00 00 FF FF FF 00 FF FF
    のようでしたら正しいはずですが。詳細は、下記を参照ください。
    http://www.kk.iij4u.or.jp/~kondo/bmp/

    これが違っているようなら、コンパイル時のオプションを確認してみてください(特にEndian関連)。
  • id:jsakato
    なんとか希望していた画像を取得できるようになりました。
    ご提示していただいたプログラムがとても参考になりました。
    ありがとうございました。またの機会がありましたら是非よろしくお願いもうしあげます。
  • id:Mook
    どうなったのか気になっていました、無事解決したようでなによりです。

    記念すべき100匹目のイルカ、ありがとうございました。

この質問への反応(ブックマークコメント)

「あの人に答えてほしい」「この質問はあの人が答えられそう」というときに、回答リクエストを送ってみてましょう。

これ以上回答リクエストを送信することはできません。制限について

絞り込み :
はてなココの「ともだち」を表示します。
回答リクエストを送信したユーザーはいません