Search code examples
skia

Skia buggy color blending


I'm using Skia m62 with Open GL backend and getting the glitch while rendering png file.

To create SkBitmap I'm using the following code:

const auto codec = SkCodec::MakeFromStream(SkStream::MakeFromFile("test.png"));
const SkImageInfo imageInfo = codec->getInfo().makeColorType(kN32_SkColorType);
SkBitmap bm;
bm.allocPixels(imageInfo);
codec->getPixels(imageInfo, bm.getPixels(), bm.rowBytes());

The rest of the code is slightly modified (cannot find gl/GrGLUtil.h header) example found in Skia sources: https://github.com/google/skia/blob/master/example/SkiaSDLExample.cpp

Picture illustrating bug

The library is built with arguments: skia_use_freetype=true skia_use_system_freetype2=false skia_use_libpng=true skia_use_system_libpng=false skia_use_expat=false skia_use_icu=false skia_use_libjpeg_turbo=false skia_use_libwebp=false skia_use_piex=false skia_use_sfntly=false skia_use_zlib=true skia_use_system_zlib=false is_official_build=true target_os="mac" target_cpu="x86_64"

Here is the FULL EXAMPLE on GitHub illustrating the issue. It contains the png under observation and full setup to run on Mac OS x86_64.

UPD: Filed a bug in Skia tracker: https://bugs.chromium.org/p/skia/issues/detail?id=7361


Solution

  • I'll quote the answer from Skia's bugtracker:

    Skia's GPU backend doesn't support drawing unpremultiplied images, but that is the natural state of most encoded images, including all .pngs. What you're seeing is an unpremultiplied bitmap being drawn as if it were a premultiplied bitmap. Pretty isn't it?

    There are a couple easy ways to fix this. The simplest way to adapt the code you have there is to make sure to ask SkCodec for premultiplied output, e.g.

    const SkImageInfo imageInfo = codec->getInfo().makeColorType(kN32_SkColorType) .makeAlphaType(kPremul_SkAlphaType);

    Or, you can use this simpler way to decode and draw:

    sk_sp img = SkImage::MakeFromEncoded(SkData::MakeFromFileName("test.png")); ... canvas->drawImage(img, ...);

    That way lets SkImage::MakeFromEncoded() make all the choices about format for you.

    This solves the issue.