Strange text discolouration in pango/cairo on Windows

Hi.

I’m working on a 3D OpenGL application that runs on Windows. I’m attempting to use pango to render rich formatted text to an transparent 32-bit offscreen bitmap which can then be plonked onto a 3D surface as an OpenGL texture.

I wrote the following test code to generate a 100x100 test bitmap.

#include <vector>
#include <functional>

#include <glib.h>
#include <pango/pangocairo.h>
#include <gsl/gsl>

int main(int argc, char **argv)
  {
  const int cx = 100;
  const int cy = 100;

  // Create Cairo surface.

  const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, cx);
  std::vector<unsigned char> buffer(static_cast<size_t>(stride * cy), 0);

  cairo_surface_t *surface = cairo_image_surface_create_for_data(buffer.data(), CAIRO_FORMAT_ARGB32,
                                                                 cx, cy, stride);
  if (cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
    return 1;
  auto destroySurface = gsl::finally([surface]() { cairo_surface_destroy(surface); });

  cairo_t *cairo = cairo_create(surface);
  if (cairo_status(cairo) != CAIRO_STATUS_SUCCESS)
    return 1;
  auto destroyCairo = gsl::finally([cairo]() { cairo_destroy(cairo); });

  // Setup Pango using Cairo renderer.

  PangoLayout *layout = pango_cairo_create_layout(cairo);
  if (!layout)
    return 1;
  auto releaseLayout = gsl::finally([layout]() { g_object_unref(layout); });

  pango_layout_set_width(layout, cx * PANGO_SCALE); // Set max width for layout before it wraps.

  static const char *markupText =
    "<span font_desc=\"Dejavu Sans 12\"><span foreground=\"#ff8040\">Pango</span> + <span foreground=\"#4080ff\">Cairo</span> Test Text</span>";
  pango_layout_set_markup(layout, markupText, -1);

  // Update/layout the pango layout and render with Cairo to our bitmap.

  pango_cairo_update_layout(cairo, layout);
  pango_cairo_show_layout(cairo, layout);

  cairo_surface_write_to_png(surface, "test.png");
  
  return 0;
  }

I chose a low resolution initially to ensure the anti-aliasing looked okay (per-pixel alpha). I would of course want something higher quality eventually. Since I am rendering to an offscreen bitmap sub-pixel rendering isn’t desirable. I’m hoping this whole idea makes sense.

Unfortunately I immediately noticed some green discolouration around the edges of the coloured text. Using cairo_surface_write_to_png to write the surface to a png I get the following:
https://imgur.com/Eat1w5X

On an Arch Linux machine running the exact same code I get the following:
https://imgur.com/XdGzFJo

On Windows I am using pango 1.50.7 and cairo 1.17.6 from vcpkg. On Arch Linux I am using pango 1.50.8 and cairo 1.17.6 from the Arch repos.

Am I doing something wrong here, or have I stumbled across a bug?

Yeah. When using the default text antialiasing option, CAIRO_ANTIALIAS_DEFAULT, Cairo/Win32 picks the setting from the system, whereas Cairo/Freetype uses grey-scale antialiasing. As I don’t think there’s a way to specify text antialiasing options in Pango markup, you’ll always end up having fonts with CAIRO_ANTIALIAS_DEFAULT. With Cairo/Win32 that means RGB antialiasing, unless Cleartype is disabled system-wide.

To solve the issue I suggest setting the environment variable PANGOCAIRO_BACKEND=fontconfig at the start of your main function. By doing so you get the same results on Windows as on Linux.

Thank you!

Setting PANGOCAIRO_BACKEND=fontconfig seems to have done the trick.

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.