Convert pycairo ARGB32 surface to PIL RGB image

Cairo is great for rendering stuff, but doesn’t give you many options to export your data. The Python Image Library has good options to save stuff. The problem I ran into is that I have a ARGB32 pycairo surface, and PIL doesn’t support ARGB32. It supports RGBA instead. After much experimentation, I came up with the following piece of code, using numpy to solve this problem:

def pilImageFromCairoSurface( surface ):
   cairoFormat = surface.get_format()
   if cairoFormat == cairo.FORMAT_ARGB32:
      pilMode = 'RGB'
      # Cairo has ARGB. Convert this to RGB for PIL which supports only RGB or
      # RGBA.
      argbArray = numpy.fromstring( surface.get_data(), 'c' ).reshape( -1, 4 )
      rgbArray = argbArray[ :, 2::-1 ]
      pilData = rgbArray.reshape( -1 ).tostring()
      raise ValueError( 'Unsupported cairo format: %d' % cairoFormat )
   pilImage = PIL.Image.frombuffer( pilMode,
         ( surface.get_width(), surface.get_height() ), pilData, "raw",
         pilMode, 0, 1 )
   pilImage = pilImage.convert( 'RGB' )
   return pilImage

This reportedly doesn’t work with python 3, which requires the “argbArray = ” line to read:

argbArray = numpy.fromstring( bytes(surface.get_data()), 'c' ).reshape( -1, 4 )

See the disqus comments below for more details.

About the author

Living the good life in Seattle, occasionally sharing something interesting with the Internet.