FreeType2のメモ

テキストをレンダリングするところまでこぎつけたので貼り付け。

// g++ -o sample -g `freetype-config --cflags` sample.cpp `freetype-config --libs`
//#include <locale.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include <string>
#include <vector>
#include <fstream>
#include <cassert>

#define FONT_SIZE 32
#define LINE_MERGIN 2

class P5
{
    int w_;
    int h_;
    std::vector<unsigned char> data_;

public:
    P5()
        : w_(0), h_(0)
    {
    }

    void resize(int w, int h, unsigned char value)
    {
        w_=w;
        h_=h;
        data_.resize(w*h, value);
    }

    void blit(int _x, int _y, const unsigned char *_src, int w, int h, int pitch)
    {
        printf("blit %d:%d\n", w, h);
        assert(_y>=0);
        for(int y=0; y<h; ++y){
            const unsigned char *src=&_src[pitch*y];
            unsigned char *dst=&data_[(_y+y)*w_+_x];
            for(int x=0; x<w; ++x, ++src, ++dst){
                *dst=*src;
            }
        }
    }

    bool write(const std::string &path)
    {
        std::ofstream io(path.c_str(), std::ios::binary);
        if(!io){
            return false;
        }

        // header
        io
            << "P5\n"
            << w_ << " " << h_ << "\n"
            << "255\n"
            ;


        // body
        io.write(reinterpret_cast<const char*>(&data_[0]), data_.size());
        
        return true;
    }
};

void face_info(const FT_Face &face)
{
    double ratio=(double)face->size->metrics.y_ppem / (double)face->units_per_EM;
    const FT_Size_Metrics &m=face->size->metrics;
    printf("height: %d, ascender: %d, descender: %d, max_advance: %d\n", 
            (int)(face->height*ratio),
            (int)(face->ascender*ratio), 
            (int)(face->descender*ratio), 
            (int)(m.max_advance*ratio)
          );
}

class Renderer
{
    int x_;
    int y_;
    P5 &image_;

public:
    Renderer(P5 &image)
        : x_(0), y_(0), image_(image)
    {}

    void new_line(int line_height)
    {
        y_+=line_height;
        x_=0;
    }

    void render(const FT_Face &face, const wchar_t *text)
    {
        FT_GlyphSlot slot = face->glyph;
        double ratio=(double)face->size->metrics.y_ppem / (double)face->units_per_EM;
        int pen_x=x_;
        // baseline(小数切り上げ)
        int pen_y=y_+(face->ascender)*ratio+1;
        printf("ratio: %f, %d-%d\n", ratio, pen_x, pen_y);

        for (const wchar_t *p=text; *p!='\0'; ++p)
        { 
            int error = FT_Load_Glyph(face,
                    FT_Get_Char_Index(face, *p),
                    FT_LOAD_RENDER );
            if ( error ){ 
                continue;
            }

            const FT_Bitmap &bitmap=slot->bitmap;
            image_.blit(pen_x+slot->bitmap_left, pen_y-slot->bitmap_top,
                    bitmap.buffer, bitmap.width, bitmap.rows, bitmap.pitch);

            pen_x += slot->advance.x >> 6;
        }
    }
};

int main(int argc, char **argv)
{
    //setlocale(LC_CTYPE, "ja_JP.utf8");

    if(argc<2){
        printf("usage: %s {font file}\n", argv[0]);
        return 1;
    }

    FT_Library library;
    int error = FT_Init_FreeType( &library );
    if ( error ) {
        printf("FT_Init_FreeType failed\n");
        return 1;
    } 

    FT_Face face;
    error = FT_New_Face(library, argv[1], 0, &face);
    if (error==FT_Err_Unknown_File_Format){
        printf("FT_Err_Unknown_File_Format\n");
        return 1;
    }
    else if(error){
        printf("FT_New_Face failed\n");
        return 1;
    }

    error = FT_Set_Pixel_Sizes( face,
            0,
            FONT_SIZE ); 
    if(error){
        printf("FT_Set_Pixel_Sizes failed\n");
        return 1;
    }

    face_info(face);

    P5 image;
    image.resize(400, 200, 0x30);

    Renderer renderer(image);
    renderer.render(face, L"AB,#?CD");
    renderer.new_line(FONT_SIZE+LINE_MERGIN);
    renderer.render(face, L"日本語マルチバイト");
    renderer.new_line(FONT_SIZE+LINE_MERGIN);
    renderer.render(face, L"efg〆★hijk");
    renderer.new_line(FONT_SIZE+LINE_MERGIN);

    image.write("tmp.pgm");

    return 0;
}

gentoo Linux上で

$ ./a.out /usr/share/fonts/ipamonafont/ipag-mona.ttf

WindowsXP上で

> main.exe C:/WINDOWS/Fonts/MSGOTHIC.TTC

としてどっちでも動作を確認できた。大丈夫だろう。
問題があるとすれば、FT_Set_Pixel_Sizesで指定した
サイズを越えてくるフォントやグリフの場合だけど、
そういうのはあるのだろうか。


baselinの算出は、
http://hp.vector.co.jp/authors/VA028002/freetype.html
を参考させていただきました。
ていうかそのままです。