mono / SkiaSharp

SkiaSharp is a cross-platform 2D graphics API for .NET platforms based on Google's Skia Graphics Library. It provides a comprehensive 2D API that can be used across mobile, server and desktop models to render images.
MIT License
4.52k stars 540 forks source link

[BUG] Supbixel Rendering does not work on Linux #1669

Open DorianRudolph opened 3 years ago

DorianRudolph commented 3 years ago

Description

Subpixel rendering does not work on Linux. The equivalent C++ does work as expected.

Code

C#

var imageInfo = new SKImageInfo(
    width: 100, 40,
    colorType: SKColorType.Bgra8888,
    alphaType: SKAlphaType.Premul);
var props = new SKSurfaceProperties(SKSurfacePropsFlags.None, SKPixelGeometry.BgrHorizontal);
var surface = SKSurface.Create(imageInfo, props);
var canvas = surface.Canvas;

var paint = new SKPaint();
var font = new SKFont {Subpixel = true, Edging = SKFontEdging.SubpixelAntialias, Size = 12};
canvas.Clear(SKColors.White);
canvas.DrawText("Hello World", 10, 20, font, paint);
using (var image = surface.Snapshot())
using (var data = image.Encode())
{
    File.WriteAllBytes("b.png", data.ToArray());
}

C++

auto info = SkImageInfo::Make(100, 40,
                              SkColorType::kBGRA_8888_SkColorType,
                              SkAlphaType::kPremul_SkAlphaType);
SkSurfaceProps props {0, SkPixelGeometry::kBGR_H_SkPixelGeometry};
auto surface = SkSurface::MakeRaster(info, &props);
auto *canvas = surface->getCanvas();

SkPaint paint;
SkFont font;
font.setSubpixel(true);
font.setEdging(SkFont::Edging::kSubpixelAntiAlias);
font.setSize(12);
canvas->clear(SK_ColorWHITE);
canvas->drawString("Hello World", 10, 20, font, paint);

auto img = surface->makeImageSnapshot();
auto data = img->encodeToData();

std::ofstream fout;
fout.open("a.png", std::ios::binary | std::ios::out);
fout.write(static_cast<const char *>(data->data()), data->size());

Expected Behavior

Output from from C++ (with subpixel AA):

a

Actual Behavior

Output From C# (no subpixel AA):

test

Basic Information

Code for 1.68.3:

paint.SubpixelText = true;
paint.LcdRenderText = true;
paint.IsAntialias = true;
canvas.Clear(SKColors.White);
canvas.DrawText("Hello World", 10, 20, paint);
DorianRudolph commented 3 years ago

After further investigation, the issue must lie in the freetype2build inside skia. When building skia with skia_use_system_freetype2=true, subpixels are rendered correctly (mono/skia requires skia.patch.txt to build).

DorianRudolph commented 3 years ago

Ah it looks like mono/skia does not yet have the patch for harmony subpixel rendering (https://skia.googlesource.com/skia/+/f25787b72c20e97cdeb74e037dc1ff56a88b45c6). For compiling, one could also enable cleartype (FT_CONFIG_OPTION_SUBPIXEL_RENDERING), but that apparently is using patented technology. The simplest fix would be to update skia or use the system freetype2.

Gillibald commented 3 years ago

Updating freetype2 should be a one-liner: https://github.com/mono/skia/blob/173debd238b1a55ab12f5994c5dc074fd141ccd6/DEPS#L15

DorianRudolph commented 3 years ago

Yes, but the patch linked above (https://skia.googlesource.com/skia/+/f25787b72c20e97cdeb74e037dc1ff56a88b45c6%5E%21/#F0) also needs to be applied. However, it apparently is now fine to enable cleartype (https://www.phoronix.com/scan.php?page=news_item&px=Fedora-ClearType-Subpixel-Font) so that is what I will do for myself.