Skiaでフォントを指定して文字列を描画する。Freetype2とHarfbuzzが必要。
Skiaでフォント使用(1)文字列描画
#pragma comment(lib,"skia.dll.lib") #pragma comment(lib,"skshaper.dll.lib") ///////////////////////////////////// #include "skia/include/core/SkCanvas.h" #include "skia/include/core/SkBitmap.h" #include "skia/include/core/SkSurface.h" #include "include/core/SkSurface.h" ///////////////////////////////////// // テキスト描画 #include "include/core/SkTypeface.h" #include "include/core/SkFont.h" #include "include/core/SkFontMgr.h" #include "include/ports/SkFontMgr_directory.h" // フォントマネージャ作成 #include "include/core/SkFontMetrics.h" // 文字のレイアウト #include "modules/skshaper/include/SkShaper.h" ///////////////////////////////////// ///////////////////////////////////// ///////////////////////////////////// // Png保存に必要 #include "include/encode/SkPngEncoder.h" #include "include/core/SkStream.h" /////////////////////////////////////
// SkShaperで文字列を描画するためのクラス class CanvasRunHandler : public SkShaper::RunHandler { public: CanvasRunHandler(SkCanvas* canvas, SkPoint origin, const SkFont& font, const SkPaint& paint) : canvas_(canvas), origin_(origin), font_(font), paint_(paint) {} void runInfo(const RunInfo& info) override { glyphCount_ = info.glyphCount; glyphs_.resize(glyphCount_); positions_.resize(glyphCount_); } Buffer runBuffer(const RunInfo& info) override { return { glyphs_.data(), // glyphs positions_.data(), // positions nullptr, // offsets nullptr, // clusters origin_ // point offset to add to all positions }; } void commitRunBuffer(const RunInfo& info) override { canvas_->drawGlyphs( glyphCount_, glyphs_.data(), positions_.data(), runOrigin_, font_, paint_ ); } void beginLine() override { } void commitRunInfo() override { } void commitLine() override { } private: SkCanvas* canvas_; SkPoint origin_; SkPoint runOrigin_; SkFont font_; SkPaint paint_; int glyphCount_ = 0; SkVector runOffset_; std::vector<SkGlyphID> glyphs_; std::vector<SkPoint> positions_; };
// テキスト描画のテスト SkBitmap TextTest() { // フォントマネージャ作成 sk_sp<SkFontMgr> fontMgr = SkFontMgr_New_Custom_Directory("C:\\Windows\\Fonts\\"); // フォントが格納されているディレクトリ指定 //auto typeface = fontMgr->matchFamilyStyle("Segoe UI Emoji", SkFontStyle::Normal()); // カラー絵文字はうまく描画できない auto typeface = fontMgr->matchFamilyStyle("MS Gothic", SkFontStyle::Normal()); // フォントの取得 /////////////////////////////////////////////////////////////////////////////////////////// SkImageInfo imginfo = SkImageInfo::Make(500, 100, kN32_SkColorType, kPremul_SkAlphaType); sk_sp<SkSurface> surface = SkSurfaces::Raster(imginfo); SkCanvas* canvas = surface->getCanvas(); canvas->clear(SK_ColorWHITE); // 背景を白にクリア /////////////////////////////////////////////////////////////////////////////////////////// // テキストの描画 SkPaint paint; paint.setColor(SK_ColorBLACK); // テキストの色 paint.setAntiAlias(false); // アンチエイリアスを有効にする /////////////////////////////////////////////////////////////////////////////////////////// // フォントの設定 SkFont font; font.setEdging(SkFont::Edging::kAntiAlias); // エッジングの設定 font.setSize(50.f * 72 / 96); // テキストのサイズ font.setTypeface(typeface); // フォントの設定 /////////////////////////////////////////////////////////////////////////////////////////// SkScalar x = 30.f; // テキストの位置(横)を設定 SkScalar y = 50.0f; // テキストの位置(縦)を設定 SkFontMetrics metrics; font.getMetrics(&metrics); y -= metrics.fAscent;// テキストの位置(高さ)を設定 /////////////////////////////////////////////////////////////////////////////////////////// // カラー絵文字はうまく描画できない //SkString text((const char*)u8"😊👩👨👦👧"); SkString text((const char*)u8"がぎぐげご"); /////////////////////////////////////////////////////////////////////////////////////////// #if 1 // テキストの描画(結合文字対応) int width = 500; std::unique_ptr<SkShaper> shaper = SkShaper::Make(); SkPoint origin = SkPoint::Make(x, y); CanvasRunHandler runHandler(canvas, origin, font, paint); shaper->shape(text.data(), strlen(text.c_str()), font, true, width, &runHandler); #else // テキストの描画 canvas->drawString(text, x, y, font, paint); #endif ////////////////////////////////////////////////// // // PNG出力 SkPixmap pixmap; if (surface->peekPixels(&pixmap)) { SkFILEWStream stream("output.png"); SkPngEncoder::Options options; options.fZLibLevel = 9; SkPngEncoder::Encode(&stream, pixmap, options); } // Bitmap化 SkBitmap bitmap; bitmap.allocPixels(imginfo); surface->readPixels(bitmap.pixmap(), 0, 0); return bitmap; }
カラー絵文字についてもフォントをSegoe UI Emojiなどにすれば一応動くのだが、デバッグモードでは正しく出力できるのにリリースモードでは透明度かなにかがおかしくなる。意味が分からない。