skip to Main Content

I copied a piece of tutorial code to my project, trying to see if it works fine on my computer. However, it renders everthing except the text. My OS is Windows 11 and IDE is Microsoft Visual Studio 2022. Below is the code:

#include <include/core/SkCanvas.h>
#include <include/core/SkBitmap.h>
#include <include/core/SkPaint.h>
#include <include/core/SkTypeface.h>
#include <include/core/SkFont.h>
#include <include/codec/SkCodec.h>
#include <include/core/SkStream.h>
#include <include/encode/SkPngEncoder.h>
#include <include/core/SkFontMgr.h>
#include "file.h"
#include <iostream>

int main(int argc, char* const argv[]) {
    SkBitmap bitmap;
    SkImageInfo imageInfo = SkImageInfo::Make(480, 320, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
    bitmap.allocPixels(imageInfo, imageInfo.minRowBytes());

    SkCanvas canvas(bitmap);
    SkPaint paint;
    canvas.clear(SkColorSetARGB(0xFF, 0x14, 0x14, 0x14));
    paint.setColor(SK_ColorWHITE);
    SkFont font;
    font.setSize(64);
    sk_sp<SkFontMgr> fontMgr = SkFontMgr::RefEmpty();
    sk_sp<SkTypeface> fTypeface = fontMgr->legacyMakeTypeface("Arial", SkFontStyle::Normal());
    font.setTypeface(fTypeface);
    SkString text("Hello, Skia!");
    canvas.drawSimpleText(text.c_str(), text.size(), SkTextEncoding::kUTF8, 0, 64, font, paint); 

    SkFILEWStream file("hello_skia.png");
    if (!file.isValid()) {
        return 1;
    }
    return SkPngEncoder::Encode(&file, bitmap.pixmap(), {});
}

The expected output should be
Expected Output
However, my code outputs
My Output

I have tried to compile skia source code for different edtions. Here are the PowerShell commmands that I have tried:

bin/gn gen out/debug --args='clang_win="C:Program FilesLLVM" cc="clang" cxx="clang++" extra_cflags=["/MTd"] is_official_build=true is_debug=false skia_use_system_expat=false skia_use_system_libjpeg_turbo=false skia_use_system_libpng=false skia_use_system_libwebp=false skia_use_system_zlib=false skia_use_system_harfbuzz=false skia_use_icu=false'

and

bin/gn gen out/all --ide=vs --args="clang_win="C:Program FilesLLVM""

For the second command, it generates all.sin for me and HelloWorld.cpp works fine, which is really confusing to me.

2

Answers


  1. Chosen as BEST ANSWER

    Found the solution to the problem. To render the text, a SkTypeface variable needs to be declared, otherwise the string will not be rendered. I guess it is because of an update so SkFont stops setting the SkTypeface parameter to default when it is not explicitly declared.


  2. I believe the correct way to get the fonts and set them for the typeface is to make use of fontConfig provided via SkFontMgr_New_FontConfig API.

    Here’s the code I got working on my system based of the above provided code and making use of SkFontMgr_New_FontConfig.

    #include <cstdint>
    #include <iostream>
    
    #include <include/core/SkCanvas.h>
    #include <include/core/SkBitmap.h>
    #include <include/core/SkColor.h>
    #include <include/core/SkImage.h>
    #include <include/core/SkStream.h>
    #include <include/core/SkSurface.h>
    #include <include/encode/SkPngEncoder.h>
    #include <include/core/SkFontMgr.h>
    #include <include/core/SkFont.h>
    #include <include/ports/SkFontMgr_fontconfig.h>
    
    void drawNewString(SkCanvas* canvas)
    {
        sk_sp<SkFontMgr> skFontManager = SkFontMgr_New_FontConfig(nullptr);
        int familyCount = skFontManager->countFamilies();
        auto typeface = SkTypeface::MakeEmpty();
    
        std::vector<std::string> fontFamilies;
        for (int i = 0; i < familyCount; ++i) {
            SkString familyName;
            skFontManager->getFamilyName(i, &familyName);
            fontFamilies.push_back(familyName.c_str());
        }
        std::cout << "Font families Size " << fontFamilies.size() << std::endl;
        auto containsFont = [&](const std::string& font) {
            return std::find(fontFamilies.begin(), fontFamilies.end(), font) != fontFamilies.end();
        };
        if (containsFont("Helvetica")) {
            typeface = skFontManager->matchFamilyStyle("Helvetica", SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kSemiCondensed_Width, SkFontStyle::kUpright_Slant));
        } else if (containsFont("Roboto Condensed")) {
            typeface = skFontManager->matchFamilyStyle("Roboto Condensed", SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kNormal_Width, SkFontStyle::kUpright_Slant));
        } else if (containsFont("Swis721 BT")) {
            typeface = skFontManager->matchFamilyStyle("Swis721 BT", SkFontStyle());
        } else if (containsFont("Arial")) {
            typeface = skFontManager->matchFamilyStyle("Arial", SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kCondensed_Width, SkFontStyle::kUpright_Slant));
        } else {
            typeface = skFontManager->matchFamilyStyle("Helvetica", SkFontStyle(SkFontStyle::kBold_Weight, SkFontStyle::kSemiCondensed_Width, SkFontStyle::kUpright_Slant));
        }
    
        if (!typeface) {
          printf("Cannot open typefacen");
          return;
        }
    
        SkPaint paint;
        canvas->clear(SkColorSetARGB(0xFF, 0x14, 0x14, 0x14));
        paint.setColor(SK_ColorWHITE);
        SkFont font;
        font.setSize(64);
        
        font.setTypeface(typeface);
        SkString text("Hello, Skia!");
        canvas->drawSimpleText(text.c_str(), text.size(), SkTextEncoding::kUTF8, 0, 64, font, paint); 
    }
    
    
    
    int main()
    {
    
        auto surface(SkSurfaces::Raster(SkImageInfo::MakeN32Premul(300, 300)));
        SkCanvas* canvas = surface->getCanvas();
    
        drawNewString(canvas);
        sk_sp<SkImage> img = canvas->getSurface()->makeImageSnapshot();
    
        if (!img) { return -1; }
    
        sk_sp<SkData> png = SkPngEncoder::Encode(nullptr, img.get(), SkPngEncoder::Options());
        if (!png) { return -1; }
    
        SkFILEWStream out("output.png");
        (void)out.write(png->data(), png->size());
    
        return 0;
    }
    

    The above code will print the number of fonts available on the machine and will create the typeface based on what font is available.

    NOTE:

    1. Make sure to install fontconfig library by running the following command:
      sudo apt-get install libfontconfig1-dev
    2. Build your code with -lfontconfig flag of target_link_libraries in your CMakeLists.

    Hope this resolves the issue of the font rendering with Skia c++.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search