Search code examples
cairofreepascallazarusgdk

How to stretch draw a cairo gdk pixbuf pattern region with an arbitrary opacity?


How can I stretch draw an area of a gdk pixbuf to a cairo surface with a user defined opacity?

I am trying to write a cross platform interface for working with bitmaps and want to add alpha blending to my cairo stretch draw method. What I have right now works just fine, but I am unable to think up a way of to mold alpha blending into a series of cairo/gdk apis which work somewhat like Microsoft's AlphaBlend function.

What I have so far is this:

procedure TGtkBitmap.Draw(const Source: TRect; Canvas: TCanvas;
  const Dest: TRect; Alpha: Byte = $FF);
var
  D: PGdkDrawable;
  C: Pcairo_t;
  M: cairo_matrix_t;
begin
  if FBuffer = nil then
    Exit;
  if (WidthOf(Source) < 1) or (WidthOf(Dest) < 1) then
    Exit;
  if (HeightOf(Source) < 1) or (HeightOf(Dest) < 1) then
    Exit;
  D := TGtk2DeviceContext(Canvas.Handle).Drawable;
  C := gdk_cairo_create(D);
  gdk_cairo_set_source_pixbuf(C, FBuffer, 0, 0);
  cairo_matrix_init_identity(@M);
  cairo_matrix_translate(@M, Source.Left, Source.Top);
  cairo_matrix_scale(@M, WidthOf(Source) / WidthOf(Dest),
    HeightOf(Source) / HeightOf(Dest));
  cairo_matrix_translate(@M, -Dest.Left, -Dest.Top);
  cairo_pattern_set_matrix(cairo_get_source(C), @M);
  cairo_rectangle(C, Dest.Left, Dest.Top, WidthOf(Dest), HeightOf(Dest));
  // what cairo functions can I combine here to vary
  // the opacity of the pattern fill using Alpha argument?
  cairo_fill(C);
  cairo_destroy(C);
end;

Everything works fine, but I am unsure how to get alpha blending with a pix buff pattern working. I can imagine one way which involves creating a second cairo surface, drawing the entire pixbuf to it with a user defined opacity, then creating pattern for the first surface using the new surface, which all gets a little messy and probably is much slower than something I'd be happy with.

Here is a video recording of what I have working so far. I'd like to know from someone familiar with cairo, what can I insert into my routine above to set the alpha level of the pixbuf source pattern?


Solution

  • Chris Wilson from the cairo mailing lists offered this solution which works perfectly.

    Replace the:

    cairo_fill(C);
    

    with:

    cairo_clip(C);
    cairo_paint_with_alpha(C, Alpha / $FF);
    

    Thanks to Chris Wilson from the cairo mailing lists!