SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

特集記事

文字コードから画像ファイルを生成する

BMP構造とCを使った画像ファイル作成の説明

  • X ポスト
  • このエントリーをはてなブックマークに追加

アンチエイリアス処理をかける

 文字を描画するときは、アンチエイリアス処理をかけた方が見栄えはよくなります。ただ、モノクロビットマップではアンチエイリアス処理の結果を反映できません。そこで、「sample1.c」を変更して、256色ビットマップファイルを出力する「sample2.c」を作成します。変更部分は太字にしています。

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

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

//RGBQUAD構造体配列
int Colors[256] = {
    0x00000000,0x00800000,0x00008000,0x00808000,
    0x00000080,0x00800080,0x00008080,0x00C0C0C0,
    0x00C0DCC0,0x00A6CAF0,0x00402000,0x00602000,
    0x00802000,0x00A02000,0x00C02000,0x00E02000,
    0x00004000,0x00204000,0x00404000,0x00604000,
    0x00804000,0x00A04000,0x00C04000,0x00E04000,
    0x00006000,0x00206000,0x00406000,0x00606000,
    0x00806000,0x00A06000,0x00C06000,0x00E06000,
    0x00008000,0x00208000,0x00408000,0x00608000,
    0x00808000,0x00A08000,0x00C08000,0x00E08000,
    0x0000A000,0x0020A000,0x0040A000,0x0060A000,
    0x0080A000,0x00A0A000,0x00C0A000,0x00E0A000,
    0x0000C000,0x0020C000,0x0040C000,0x0060C000,
    0x0080C000,0x00A0C000,0x00C0C000,0x00E0C000,
    0x0000E000,0x0020E000,0x0040E000,0x0060E000,
    0x0080E000,0x00A0E000,0x00C0E000,0x00E0E000,
    0x00000040,0x00200040,0x00400040,0x00600040,
    0x00800040,0x00A00040,0x00C00040,0x00E00040,
    0x00002040,0x00202040,0x00402040,0x00602040,
    0x00802040,0x00A02040,0x00C02040,0x00E02040,
    0x00004040,0x00204040,0x00404040,0x00604040,
    0x00804040,0x00A04040,0x00C04040,0x00E04040,
    0x00006040,0x00206040,0x00406040,0x00606040,
    0x00806040,0x00A06040,0x00C06040,0x00E06040,
    0x00008040,0x00208040,0x00408040,0x00608040,
    0x00808040,0x00A08040,0x00C08040,0x00E08040,
    0x0000A040,0x0020A040,0x0040A040,0x0060A040,
    0x0080A040,0x00A0A040,0x00C0A040,0x00E0A040,
    0x0000C040,0x0020C040,0x0040C040,0x0060C040,
    0x0080C040,0x00A0C040,0x00C0C040,0x00E0C040,
    0x0000E040,0x0020E040,0x0040E040,0x0060E040,
    0x0080E040,0x00A0E040,0x00C0E040,0x00E0E040,
    0x00000080,0x00200080,0x00400080,0x00600080,
    0x00800080,0x00A00080,0x00C00080,0x00E00080,
    0x00002080,0x00202080,0x00402080,0x00602080,
    0x00802080,0x00A02080,0x00C02080,0x00E02080,
    0x00004080,0x00204080,0x00404080,0x00604080,
    0x00804080,0x00A04080,0x00C04080,0x00E04080,
    0x00006080,0x00206080,0x00406080,0x00606080,
    0x00806080,0x00A06080,0x00C06080,0x00E06080,
    0x00008080,0x00208080,0x00408080,0x00608080,
    0x00808080,0x00A08080,0x00C08080,0x00E08080,
    0x0000A080,0x0020A080,0x0040A080,0x0060A080,
    0x0080A080,0x00A0A080,0x00C0A080,0x00E0A080,
    0x0000C080,0x0020C080,0x0040C080,0x0060C080,
    0x0080C080,0x00A0C080,0x00C0C080,0x00E0C080,
    0x0000E080,0x0020E080,0x0040E080,0x0060E080,
    0x0080E080,0x00A0E080,0x00C0E080,0x00E0E080,
    0x000000C0,0x002000C0,0x004000C0,0x006000C0,
    0x008000C0,0x00A000C0,0x00C000C0,0x00E000C0,
    0x000020C0,0x002020C0,0x004020C0,0x006020C0,
    0x008020C0,0x00A020C0,0x00C020C0,0x00E020C0,
    0x000040C0,0x002040C0,0x004040C0,0x006040C0,
    0x008040C0,0x00A040C0,0x00C040C0,0x00E040C0,
    0x000060C0,0x002060C0,0x004060C0,0x006060C0,
    0x008060C0,0x00A060C0,0x00C060C0,0x00E060C0,
    0x000080C0,0x002080C0,0x004080C0,0x006080C0,
    0x008080C0,0x00A080C0,0x00C080C0,0x00E080C0,
    0x0000A0C0,0x0020A0C0,0x0040A0C0,0x0060A0C0,
    0x0080A0C0,0x00A0A0C0,0x00C0A0C0,0x00E0A0C0,
    0x0000C0C0,0x0020C0C0,0x0040C0C0,0x0060C0C0,
    0x0080C0C0,0x00A0C0C0,0x00FFFBF0,0x00A0A0A4,
    0x00808080,0x00FF0000,0x0000FF00,0x00FFFF00,
    0x000000FF,0x00FF00FF,0x0000FFFF,0x00FFFFFF,
};

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

//フォント作成用関数
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;
    //ANTIALIASED_QUALITYに設定する
    lf.lfQuality = ANTIALIASED_QUALITY;
    lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
    lstrcpy(lf.lfFaceName,FontName);
    return CreateFontIndirect(&lf);
}

//文字描画関数
//Unicode(UTF-16)をいったん文字列に変換してから
//TextOutWで文字を出力する
void DrawChar(HDC hdc,int CharCode,int FontSize){
    wchar_t ws[3];
    SIZE size;
    if(CharCode < 0x10000){
        //サロゲートペアでない場合
        ws[0] = CharCode;
        ws[1] = '\0';
    }
    else{
        //サロゲートペアだった場合
        ws[0] = 0xD800 + (CharCode - 0x10000) / 0x400;
        ws[1] = 0xDC00 + (CharCode - 0x10000) % 0x400;
        ws[2] = '\0';
    }
    //半角文字を考慮して中央に描画する
    GetTextExtentPoint32W(hdc, ws, lstrlenW(ws),&size);
    TextOutW(hdc,(FontSize - size.cx) / 2,0,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 = 8;        //256色ビットマップの場合は8
    lpbmpih->biSizeImage = SizeImage;
}
 :
 :(中略)
 :

//画像ファイルを変更
int main(void){
    CharCodeToBitmapFile(0x3042,"MS 明朝",100,".\\004.bmp");//あ
    CharCodeToBitmapFile(0x4E9C,"MS ゴシック",200,".\\005.bmp");//亜
    CharCodeToBitmapFile(0x20B9F,"MS 明朝",300,".\\006.bmp");
                                                //叱(サロゲートペア)
    return 0;
}
アンチエイリアスをサポートするフォントの大きさについて
 MSDNのLOGFONT構造体の説明によると、フォントのサイズが小さすぎたり大きすぎたりした場合、アンチエイリアスがかからないことがあるようです。筆者が「MS 明朝」で「あ」の文字で試したところ、フォントサイズが48ピクセル以下または401ピクセル以上のときにアンチエイリアスはかかりませんでした。

まとめ

 以上で、解説を終わりますが、今回はデバイスコンテキストにGDI関数で描画してその内容をビットマップファイルへ保存しました。ただ、ほかにも同様の機能を実現する方法はいくつかあります。

 WindowsAPIのGetGlyphOutlineを使えば、文字の情報にダイレクトにアクセスできます。また、GDやImageMagickのような画像処理系のライブラリを使って、画像を動的に作成する方法もあります。詳しくは参考資料のURLを参照してください。

参考資料

  1. 近藤正芳のウェブページ『BMP ファイルフォーマット
  2. うめっきぃ『Bitmapファイルフォーマット
  3. Windowsプログラミング研究所『DDB→DIB変換
  4. Wikipedia『アンチエイリアス
  5. MSDN『LOGFONT
  6. EternalWindows『アンチエイリアシング
  7. 68user's page『画像生成
  8. Cepheid『ImageMagickの使用例 - 画像へ文字を記入する
修正履歴

この記事は参考になりましたか?

  • X ポスト
  • このエントリーをはてなブックマークに追加
特集記事連載記事一覧

もっと読む

この記事の著者

さなみ(サナミ)

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

  • X ポスト
  • このエントリーをはてなブックマークに追加
CodeZine(コードジン)
https://codezine.jp/article/detail/1643 2008/01/18 23:31

おすすめ

アクセスランキング

アクセスランキング

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー

アクセスランキング

アクセスランキング