mirror of
https://github.com/wxWidgets/Phoenix.git
synced 2026-01-07 04:20:07 +01:00
* Refactor wx.lib.wxcairo to a subpackage.
* Add support for using cairocffi instead of PyCairo.
This commit is contained in:
@@ -4,7 +4,7 @@ import wx
|
||||
import math
|
||||
|
||||
try:
|
||||
import wx.lib.wxcairo
|
||||
import wx.lib.wxcairo as wxcairo
|
||||
import cairo
|
||||
haveCairo = True
|
||||
except ImportError:
|
||||
@@ -45,7 +45,7 @@ class TestPanel(wx.Panel):
|
||||
dc.DrawLine(x, 0, 0, y)
|
||||
|
||||
# now draw something with cairo
|
||||
ctx = wx.lib.wxcairo.ContextFromDC(dc)
|
||||
ctx = wxcairo.ContextFromDC(dc)
|
||||
ctx.set_line_width(15)
|
||||
ctx.move_to(125, 25)
|
||||
ctx.line_to(225, 225)
|
||||
@@ -71,7 +71,7 @@ class TestPanel(wx.Panel):
|
||||
ctx.fill()
|
||||
|
||||
# Draw some text
|
||||
face = wx.lib.wxcairo.FontFaceFromFont(
|
||||
face = wxcairo.FontFaceFromFont(
|
||||
wx.FFont(10, wx.FONTFAMILY_SWISS, wx.FONTFLAG_BOLD))
|
||||
ctx.set_font_face(face)
|
||||
ctx.set_font_size(60)
|
||||
@@ -113,13 +113,13 @@ class TestPanel(wx.Panel):
|
||||
# the expected result. The other platforms are okay.
|
||||
bmp = wx.Bitmap(opj('bitmaps/toucan.png'))
|
||||
#bmp = wx.Bitmap(opj('bitmaps/splash.png'))
|
||||
img = wx.lib.wxcairo.ImageSurfaceFromBitmap(bmp)
|
||||
img = wxcairo.ImageSurfaceFromBitmap(bmp)
|
||||
|
||||
ctx.set_source_surface(img, 70, 230)
|
||||
ctx.paint()
|
||||
|
||||
# this is how to convert an image surface to a wx.Bitmap
|
||||
bmp2 = wx.lib.wxcairo.BitmapFromImageSurface(img)
|
||||
bmp2 = wxcairo.BitmapFromImageSurface(img)
|
||||
dc.DrawBitmap(bmp2, 280, 300)
|
||||
|
||||
|
||||
@@ -155,7 +155,7 @@ class TestPanel(wx.Panel):
|
||||
if not haveCairo:
|
||||
from wx.lib.msgpanel import MessagePanel
|
||||
def runTest(frame, nb, log):
|
||||
win = MessagePanel(nb, 'This demo requires the Pycairo package,\n'
|
||||
win = MessagePanel(nb, 'This demo requires the PyCairo package,\n'
|
||||
'or there is some other unmet dependency.',
|
||||
'Sorry', wx.ICON_WARNING)
|
||||
return win
|
||||
@@ -169,17 +169,16 @@ else:
|
||||
|
||||
if haveCairo:
|
||||
extra = "\n<h3>wx.lib.wxcairo</h3>\n%s" % (
|
||||
wx.lib.wxcairo.__doc__.replace('\n\n', '\n<p>'))
|
||||
wxcairo.__doc__.replace('\n\n', '\n<p>'))
|
||||
else:
|
||||
extra = '\n<p>See the docstring in the wx.lib.wxcairo module for details about installing dependencies.'
|
||||
|
||||
|
||||
|
||||
overview = """<html><body>
|
||||
<h2><center>Cairo Integration</center></h2>
|
||||
|
||||
This sample shows how to draw on a DC using the cairo 2D graphics
|
||||
library and the pycairo Python extension module that wraps the cairo
|
||||
library and either the PyCairo or cairocffi package which wrap the cairo
|
||||
API. For more information about cairo please see
|
||||
http://cairographics.org/.
|
||||
|
||||
|
||||
@@ -66,7 +66,8 @@ class TestPanel(wx.Panel):
|
||||
|
||||
def OnListBoxSelect(self, evt):
|
||||
snippet_file = opj('snippets/%s.py' % evt.GetString())
|
||||
text = file(snippet_file).read()
|
||||
with open(snippet_file) as f:
|
||||
text = f.read()
|
||||
self.canvas.SetSnippet(text)
|
||||
self.editor.SetValue(text)
|
||||
|
||||
@@ -99,10 +100,10 @@ overview = """<html><body>
|
||||
<h2><center>Cairo Integration</center></h2>
|
||||
|
||||
The wx.lib.wxcairo module provides a bit of glue that will allow you to
|
||||
use the Pycairo package drawing directly on wx.DC's.
|
||||
use the PyCairo or cairocffi packages to do Cairo drawing directly on wx.DC's.
|
||||
|
||||
<p> This sample draws the standard 'snippet' examples that come with
|
||||
the Pycairo pacakge, and a few others. The C version of the samples
|
||||
the PyCairo package, and a few others. The C version of the samples
|
||||
can be seen at http://cairographics.org/samples/
|
||||
|
||||
<p> In most snippets you'll see a call to a snippet_normalize()
|
||||
|
||||
134
wx/lib/wxcairo/__init__.py
Normal file
134
wx/lib/wxcairo/__init__.py
Normal file
@@ -0,0 +1,134 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wx.lib.wxcairo
|
||||
# Purpose: Glue code to allow either the PyCairo package or the
|
||||
# cairocffi package to be used with a wx.DC as the cairo
|
||||
# surface.
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 3-Sept-2008
|
||||
# Copyright: (c) 2008-2016 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#
|
||||
# Tags: phoenix-port, py3-port
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
This package provides some glue code that allows the Cairo library to draw
|
||||
directly on wx.DCs, convert to/from wx.Bitmaps, etc. using either the PyCairo
|
||||
or the newer cairocffi Cairo wrappers. In Cairo terms, the DC is the
|
||||
drawing surface. The `CairoContextFromDC` function in this module
|
||||
will return an instance of the Cairo Context class that is ready for
|
||||
drawing, using the native cairo surface type for the current platform.
|
||||
|
||||
Be sure to import wx.lib.wxcairo before importing the cairo module.
|
||||
|
||||
To use Cairo with wxPython you will need to have a few dependencies
|
||||
installed. On Linux and other unix-like systems you may already have
|
||||
them, or can easily get them with your system's package manager. Just
|
||||
check if libcairo and either cairocffi or pycairo are installed.
|
||||
|
||||
On Mac you can get Cairo from MacPorts or similar services. Make sure that
|
||||
the quartz option is turned on so those Mac-specific APIs will be included in
|
||||
the Cairo library when it is built. You can then use ``pip install cairocffi``
|
||||
to get the Python wrappers.
|
||||
|
||||
On Windows you can get a Cairo DLL from here:
|
||||
|
||||
http://www.gtk.org/download/windows.php
|
||||
|
||||
You'll also want to get the zlib and libpng binaries from the same place. Once
|
||||
you get those files extract the DLLs from each of the zip files and copy them
|
||||
to some place on your PATH. Finally, install the cairocffi package with pip
|
||||
to get the Python wrappers for the Cairo library.
|
||||
"""
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
import wx
|
||||
|
||||
# Import our glue functions for either cairocffi or pycairo, depending on
|
||||
# which is installed.
|
||||
try:
|
||||
# Use cairocffi first if it is available
|
||||
from .wx_cairocffi import _ContextFromDC, _FontFaceFromFont
|
||||
import cairo
|
||||
except ImportError:
|
||||
try:
|
||||
# otherwise use pycairo
|
||||
from .wx_pycairo import _ContextFromDC, _FontFaceFromFont
|
||||
import cairo
|
||||
except ImportError:
|
||||
# or provide some exception raising stubs instead
|
||||
def _ContextFromDC(dc):
|
||||
raise NotImplementedError("Cairo wrappers not found")
|
||||
|
||||
def _FontFaceFromFont(font):
|
||||
raise NotImplementedError("Cairo wrappers not found")
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def ContextFromDC(dc):
|
||||
"""
|
||||
Creates and returns a Cairo context object using the :class:`wx.DC` as the
|
||||
surface. (Only window, client, paint and memory DC's are allowed at this
|
||||
time.)
|
||||
"""
|
||||
return _ContextFromDC(dc)
|
||||
|
||||
|
||||
def FontFaceFromFont(font):
|
||||
"""
|
||||
Creates and returns a cairo.FontFace object from the native
|
||||
information in a :class:`wx.Font`.
|
||||
"""
|
||||
return _FontFaceFromFont(font)
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# wxBitmap <--> ImageSurface
|
||||
|
||||
def BitmapFromImageSurface(surface):
|
||||
"""
|
||||
Create a wx.Bitmap from a Cairo ImageSurface.
|
||||
"""
|
||||
format = surface.get_format()
|
||||
if format not in [cairo.FORMAT_ARGB32, cairo.FORMAT_RGB24]:
|
||||
raise TypeError("Unsupported format")
|
||||
|
||||
width = surface.get_width()
|
||||
height = surface.get_height()
|
||||
stride = surface.get_stride()
|
||||
data = surface.get_data()
|
||||
if format == cairo.FORMAT_ARGB32:
|
||||
fmt = wx.BitmapBufferFormat_ARGB32
|
||||
else:
|
||||
fmt = wx.BitmapBufferFormat_RGB32
|
||||
|
||||
bmp = wx.Bitmap(width, height, 32)
|
||||
bmp.CopyFromBuffer(data, fmt, stride)
|
||||
return bmp
|
||||
|
||||
|
||||
def ImageSurfaceFromBitmap(bitmap):
|
||||
"""
|
||||
Create an ImageSurface from a wx.Bitmap
|
||||
"""
|
||||
width, height = bitmap.GetSize()
|
||||
if bitmap.ConvertToImage().HasAlpha():
|
||||
format = cairo.FORMAT_ARGB32
|
||||
fmt = wx.BitmapBufferFormat_ARGB32
|
||||
else:
|
||||
format = cairo.FORMAT_RGB24
|
||||
fmt = wx.BitmapBufferFormat_RGB32
|
||||
|
||||
try:
|
||||
stride = cairo.ImageSurface.format_stride_for_width(format, width)
|
||||
except AttributeError:
|
||||
stride = width * 4
|
||||
|
||||
surface = cairo.ImageSurface(format, width, height)
|
||||
bitmap.CopyToBuffer(surface.get_data(), fmt, stride)
|
||||
surface.mark_dirty()
|
||||
return surface
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
129
wx/lib/wxcairo/wx_cairocffi.py
Normal file
129
wx/lib/wxcairo/wx_cairocffi.py
Normal file
@@ -0,0 +1,129 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wx_cairocffi
|
||||
# Purpose: wx.lib.wxcairo implementation functions for cairocffi
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 19-July-2016
|
||||
# Copyright: (c) 2016 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#
|
||||
# Tags: phoenix-port, py3-port
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
wx.lib.wxcairo implementation functions using cairocffi.
|
||||
"""
|
||||
|
||||
import wx
|
||||
|
||||
import cairocffi
|
||||
from cairocffi import cairo as cairo_c
|
||||
from cairocffi import ffi
|
||||
|
||||
# Make it so subsequent `import cairo` statements still work as if it
|
||||
# was really PyCairo
|
||||
cairocffi.install_as_pycairo()
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
# a convenience function, just to save a bit of typing below
|
||||
def voidp(ptr):
|
||||
"""Convert a SIP void* type to a ffi cdata"""
|
||||
return ffi.cast('void *', int(ptr))
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def _ContextFromDC(dc):
|
||||
if not isinstance(dc, wx.WindowDC) and not isinstance(dc, wx.MemoryDC):
|
||||
raise TypeError("Only window and memory DC's are supported at this time.")
|
||||
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
width, height = dc.GetSize()
|
||||
|
||||
# use the CGContextRef of the DC to make the cairo surface
|
||||
cgc = dc.GetHandle()
|
||||
assert cgc is not None and int(cgc) != 0, "Unable to get CGContext from DC."
|
||||
ptr = voidp(cgc)
|
||||
surfaceptr = cairo_c.cairo_quartz_surface_create_for_cg_context(
|
||||
ptr, width, height)
|
||||
surface = cairocffi.Surface._from_pointer(surfaceptr, False)
|
||||
|
||||
# Now create a cairo context for that surface
|
||||
ctx = cairocffi.Context(surface)
|
||||
|
||||
|
||||
elif 'wxMSW' in wx.PlatformInfo:
|
||||
# Similarly, get the HDC and create a surface from it
|
||||
hdc = dc.GetHandle()
|
||||
surfaceptr = cairo_c.cairo_win32_surface_create(hdc)
|
||||
surface = cairocffi.Surface._from_pointer(surfaceptr, False)
|
||||
|
||||
# Now create a cairo context for that surface
|
||||
ctx = cairocffi.Context(surface)
|
||||
|
||||
|
||||
elif 'wxGTK' in wx.PlatformInfo:
|
||||
if 'gtk3' in wx.PlatformInfo:
|
||||
# With wxGTK3, GetHandle() returns a cairo context directly
|
||||
ctxptr = voidp( dc.GetHandle() )
|
||||
|
||||
# pyCairo will try to destroy it so we need to increase ref count
|
||||
cairoLib.cairo_reference(ctxptr)
|
||||
else:
|
||||
# Get the GdkDrawable from the dc
|
||||
drawable = voidp( dc.GetHandle() )
|
||||
|
||||
# Call a GDK API to create a cairo context
|
||||
ctxptr = gdkLib.gdk_cairo_create(drawable)
|
||||
|
||||
# Turn it into a pycairo context object
|
||||
ctx = pycairoAPI.Context_FromContext(ctxptr, pycairoAPI.Context_Type, None)
|
||||
|
||||
else:
|
||||
raise NotImplementedError("Help me, I'm lost...")
|
||||
|
||||
return ctx
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def _FontFaceFromFont(font):
|
||||
if 'wxMac' in wx.PlatformInfo:
|
||||
cgFont = voidp(font.OSXGetCGFont())
|
||||
fontfaceptr = cairo_c.cairo_quartz_font_face_create_for_cgfont(cgFont)
|
||||
fontface = cairocffi.FontFace._from_pointer(fontfaceptr, False)
|
||||
|
||||
elif 'wxMSW' in wx.PlatformInfo:
|
||||
hfont = voidp(font.GetHFONT())
|
||||
fontfaceptr = cairo_c.cairo_win32_font_face_create_for_hfont(hfont)
|
||||
fontface = cairocffi.FontFace._from_pointer(fontfaceptr, False)
|
||||
|
||||
elif 'wxGTK' in wx.PlatformInfo:
|
||||
# wow, this is a hell of a lot of steps...
|
||||
desc = voidp( font.GetPangoFontDescription() )
|
||||
|
||||
pcfm = voidp(pcLib.pango_cairo_font_map_get_default())
|
||||
|
||||
pctx = voidp(gdkLib.gdk_pango_context_get())
|
||||
|
||||
pfnt = voidp( pcLib.pango_font_map_load_font(pcfm, pctx, desc) )
|
||||
|
||||
scaledfontptr = voidp( pcLib.pango_cairo_font_get_scaled_font(pfnt) )
|
||||
|
||||
fontfaceptr = voidp(cairoLib.cairo_scaled_font_get_font_face(scaledfontptr))
|
||||
cairoLib.cairo_font_face_reference(fontfaceptr)
|
||||
|
||||
fontface = pycairoAPI.FontFace_FromFontFace(fontfaceptr)
|
||||
|
||||
gdkLib.g_object_unref(pctx)
|
||||
|
||||
else:
|
||||
raise NotImplementedError("Help me, I'm lost...")
|
||||
|
||||
return fontface
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
@@ -1,56 +1,20 @@
|
||||
#----------------------------------------------------------------------
|
||||
# Name: wx.lib.wxcairo
|
||||
# Purpose: Glue code to allow the pycairo package to be used
|
||||
# with a wx.DC as the cairo surface.
|
||||
# Name: wx_pycairo
|
||||
# Purpose: wx.lib.wxcairo implementation functions for PyCairo
|
||||
#
|
||||
# Author: Robin Dunn
|
||||
#
|
||||
# Created: 3-Sept-2008
|
||||
# Copyright: (c) 2008 by Total Control Software
|
||||
# Copyright: (c) 2008-2016 by Total Control Software
|
||||
# Licence: wxWindows license
|
||||
#
|
||||
# Tags: phoenix-port, py3-port
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
"""
|
||||
This module provides some glue code that allows the pycairo package to
|
||||
be used for drawing direclty on wx.DCs. In cairo terms, the DC is the
|
||||
drawing surface. The `CairoContextFromDC` function in this module
|
||||
will return an instance of the pycairo Context class that is ready for
|
||||
drawing, using the native cairo surface type for the current platform.
|
||||
|
||||
This module requires the pycairo package, and makes use of ctypes for
|
||||
fetching the pycairo C API and also for digging into the cairo library
|
||||
itself.
|
||||
|
||||
To use Cairo with wxPython you will need to have a few dependencies
|
||||
installed. On Linux and other unix-like systems you may already have
|
||||
them, or can easily get them with your system's package manager. Just
|
||||
check if libcairo and pycairo are installed.
|
||||
|
||||
On Mac you can get Cairo from MacPorts or Fink. If you are also using
|
||||
MacPorts or Fink for your Python installation then you should be able
|
||||
to get pycairo the same way. Otherwise it's real easy to build and
|
||||
install pycairo for the Python framework installation. Just get the
|
||||
source tarball from http://pypi.python.org/pypi/pycairo and do the
|
||||
normal 'python setup.py install' dance.
|
||||
|
||||
On Windows you can get a Cairo DLL from here:
|
||||
|
||||
http://www.gtk.org/download/win32.php
|
||||
|
||||
You'll also want to get the zlib and libpng binaries from the same
|
||||
page. Once you get those files extract the DLLs from each of the zip
|
||||
files and copy them to some place on your PATH. Finally, there is an
|
||||
installer for the pycairo pacakge here:
|
||||
|
||||
http://wxpython.org/cairo/
|
||||
|
||||
wx.lib.wxcairo implementation functions using PyCairo.
|
||||
"""
|
||||
|
||||
# TODO: Support printer surfaces?
|
||||
|
||||
|
||||
import wx
|
||||
from six import PY3
|
||||
|
||||
@@ -75,7 +39,7 @@ def voidp(ptr):
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def ContextFromDC(dc):
|
||||
def _ContextFromDC(dc):
|
||||
"""
|
||||
Creates and returns a Cairo context object using the wxDC as the
|
||||
surface. (Only window, client, paint and memory DC's are allowed
|
||||
@@ -138,7 +102,7 @@ def ContextFromDC(dc):
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
def FontFaceFromFont(font):
|
||||
def _FontFaceFromFont(font):
|
||||
"""
|
||||
Creates and returns a cairo.FontFace object from the native
|
||||
information in a wx.Font.
|
||||
@@ -180,54 +144,6 @@ def FontFaceFromFont(font):
|
||||
return fontface
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# wxBitmap <--> ImageSurface
|
||||
|
||||
def BitmapFromImageSurface(surface):
|
||||
"""
|
||||
Create a wx.Bitmap from a Cairo ImageSurface.
|
||||
"""
|
||||
format = surface.get_format()
|
||||
if format not in [cairo.FORMAT_ARGB32, cairo.FORMAT_RGB24]:
|
||||
raise TypeError("Unsupported format")
|
||||
|
||||
width = surface.get_width()
|
||||
height = surface.get_height()
|
||||
stride = surface.get_stride()
|
||||
data = surface.get_data()
|
||||
if format == cairo.FORMAT_ARGB32:
|
||||
fmt = wx.BitmapBufferFormat_ARGB32
|
||||
else:
|
||||
fmt = wx.BitmapBufferFormat_RGB32
|
||||
|
||||
bmp = wx.Bitmap(width, height, 32)
|
||||
bmp.CopyFromBuffer(data, fmt, stride)
|
||||
return bmp
|
||||
|
||||
|
||||
def ImageSurfaceFromBitmap(bitmap):
|
||||
"""
|
||||
Create an ImageSurface from a wx.Bitmap
|
||||
"""
|
||||
width, height = bitmap.GetSize()
|
||||
if bitmap.ConvertToImage().HasAlpha():
|
||||
format = cairo.FORMAT_ARGB32
|
||||
fmt = wx.BitmapBufferFormat_ARGB32
|
||||
else:
|
||||
format = cairo.FORMAT_RGB24
|
||||
fmt = wx.BitmapBufferFormat_RGB32
|
||||
|
||||
try:
|
||||
stride = cairo.ImageSurface.format_stride_for_width(format, width)
|
||||
except AttributeError:
|
||||
stride = width * 4
|
||||
|
||||
surface = cairo.ImageSurface(format, width, height)
|
||||
bitmap.CopyToBuffer(surface.get_data(), fmt, stride)
|
||||
surface.mark_dirty()
|
||||
return surface
|
||||
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
# Only implementation helpers after this point
|
||||
#----------------------------------------------------------------------------
|
||||
@@ -321,7 +237,7 @@ def _findAppSvcLib():
|
||||
|
||||
#----------------------------------------------------------------------------
|
||||
|
||||
# Pycairo exports a C API in a structure via a PyCObject. Using
|
||||
# PyCairo exports a C API in a structure via a PyCObject. Using
|
||||
# ctypes will let us use that API from Python too. We'll use it to
|
||||
# convert a C pointer value to pycairo objects. The information about
|
||||
# this API structure is gleaned from pycairo.h.
|
||||
Reference in New Issue
Block a user