Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
enable / agg / agg.py
Size: Mime:
# This file was automatically generated by SWIG (http://www.swig.org).
# Version 4.0.2
#
# Do not make changes to this file unless you know what you are doing--modify
# the SWIG interface file instead.

from sys import version_info as _swig_python_version_info
if _swig_python_version_info < (2, 7, 0):
    raise RuntimeError("Python 2.7 or later required")

# Import the low-level C/C++ module
if __package__ or "." in __name__:
    from . import _agg
else:
    import _agg

try:
    import builtins as __builtin__
except ImportError:
    import __builtin__

def _swig_repr(self):
    try:
        strthis = "proxy of " + self.this.__repr__()
    except __builtin__.Exception:
        strthis = ""
    return "<%s.%s; %s >" % (self.__class__.__module__, self.__class__.__name__, strthis,)


def _swig_setattr_nondynamic_instance_variable(set):
    def set_instance_attr(self, name, value):
        if name == "thisown":
            self.this.own(value)
        elif name == "this":
            set(self, name, value)
        elif hasattr(self, name) and isinstance(getattr(type(self), name), property):
            set(self, name, value)
        else:
            raise AttributeError("You cannot add instance attributes to %s" % self)
    return set_instance_attr


def _swig_setattr_nondynamic_class_variable(set):
    def set_class_attr(cls, name, value):
        if hasattr(cls, name) and not isinstance(getattr(cls, name), property):
            set(cls, name, value)
        else:
            raise AttributeError("You cannot add class attributes to %s" % cls)
    return set_class_attr


def _swig_add_metaclass(metaclass):
    """Class decorator for adding a metaclass to a SWIG wrapped class - a slimmed down version of six.add_metaclass"""
    def wrapper(cls):
        return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy())
    return wrapper


class _SwigNonDynamicMeta(type):
    """Meta class to enforce nondynamic attributes (no new attributes) for a class"""
    __setattr__ = _swig_setattr_nondynamic_class_variable(type.__setattr__)



def iround(*args):
    return _agg.iround(*args)

def uround(*args):
    return _agg.uround(*args)

def ifloor(*args):
    return _agg.ifloor(*args)

def ufloor(*args):
    return _agg.ufloor(*args)

def iceil(*args):
    return _agg.iceil(*args)

def uceil(*args):
    return _agg.uceil(*args)
cover_shift = _agg.cover_shift
cover_size = _agg.cover_size
cover_mask = _agg.cover_mask
cover_none = _agg.cover_none
cover_full = _agg.cover_full
poly_subpixel_shift = _agg.poly_subpixel_shift
poly_subpixel_scale = _agg.poly_subpixel_scale
poly_subpixel_mask = _agg.poly_subpixel_mask
fill_non_zero = _agg.fill_non_zero
fill_even_odd = _agg.fill_even_odd

def deg2rad(*args):
    return _agg.deg2rad(*args)

def rad2deg(*args):
    return _agg.rad2deg(*args)
path_cmd_stop = _agg.path_cmd_stop
path_cmd_move_to = _agg.path_cmd_move_to
path_cmd_line_to = _agg.path_cmd_line_to
path_cmd_curve3 = _agg.path_cmd_curve3
path_cmd_curve4 = _agg.path_cmd_curve4
path_cmd_curveN = _agg.path_cmd_curveN
path_cmd_catrom = _agg.path_cmd_catrom
path_cmd_ubspline = _agg.path_cmd_ubspline
path_cmd_end_poly = _agg.path_cmd_end_poly
path_cmd_mask = _agg.path_cmd_mask
path_flags_none = _agg.path_flags_none
path_flags_ccw = _agg.path_flags_ccw
path_flags_cw = _agg.path_flags_cw
path_flags_close = _agg.path_flags_close
path_flags_mask = _agg.path_flags_mask

def is_vertex(*args):
    return _agg.is_vertex(*args)

def is_drawing(*args):
    return _agg.is_drawing(*args)

def is_stop(*args):
    return _agg.is_stop(*args)

def is_move_to(*args):
    return _agg.is_move_to(*args)

def is_line_to(*args):
    return _agg.is_line_to(*args)

def is_curve(*args):
    return _agg.is_curve(*args)

def is_curve3(*args):
    return _agg.is_curve3(*args)

def is_curve4(*args):
    return _agg.is_curve4(*args)

def is_end_poly(*args):
    return _agg.is_end_poly(*args)

def is_close(*args):
    return _agg.is_close(*args)

def is_next_poly(*args):
    return _agg.is_next_poly(*args)

def is_cw(*args):
    return _agg.is_cw(*args)

def is_ccw(*args):
    return _agg.is_ccw(*args)

def is_oriented(*args):
    return _agg.is_oriented(*args)

def is_closed(*args):
    return _agg.is_closed(*args)

def get_close_flag(*args):
    return _agg.get_close_flag(*args)

def clear_orientation(*args):
    return _agg.clear_orientation(*args)

def get_orientation(*args):
    return _agg.get_orientation(*args)

def set_orientation(*args):
    return _agg.set_orientation(*args)
CAP_ROUND = _agg.CAP_ROUND
CAP_BUTT = _agg.CAP_BUTT
CAP_SQUARE = _agg.CAP_SQUARE
JOIN_ROUND = _agg.JOIN_ROUND
JOIN_BEVEL = _agg.JOIN_BEVEL
JOIN_MITER = _agg.JOIN_MITER
FILL = _agg.FILL
EOF_FILL = _agg.EOF_FILL
STROKE = _agg.STROKE
FILL_STROKE = _agg.FILL_STROKE
EOF_FILL_STROKE = _agg.EOF_FILL_STROKE
NORMAL = _agg.NORMAL
BOLD = _agg.BOLD
ITALIC = _agg.ITALIC
TEXT_FILL = _agg.TEXT_FILL
TEXT_STROKE = _agg.TEXT_STROKE
TEXT_FILL_STROKE = _agg.TEXT_FILL_STROKE
TEXT_INVISIBLE = _agg.TEXT_INVISIBLE
TEXT_FILL_CLIP = _agg.TEXT_FILL_CLIP
TEXT_STROKE_CLIP = _agg.TEXT_STROKE_CLIP
TEXT_FILL_STROKE_CLIP = _agg.TEXT_FILL_STROKE_CLIP
TEXT_CLIP = _agg.TEXT_CLIP
nearest = _agg.nearest
bilinear = _agg.bilinear
bicubic = _agg.bicubic
spline16 = _agg.spline16
spline36 = _agg.spline36
sinc64 = _agg.sinc64
sinc144 = _agg.sinc144
sinc256 = _agg.sinc256
blackman64 = _agg.blackman64
blackman100 = _agg.blackman100
blackman256 = _agg.blackman256
pix_format_undefined = _agg.pix_format_undefined
pix_format_gray8 = _agg.pix_format_gray8
pix_format_rgb555 = _agg.pix_format_rgb555
pix_format_rgb565 = _agg.pix_format_rgb565
pix_format_rgb24 = _agg.pix_format_rgb24
pix_format_bgr24 = _agg.pix_format_bgr24
pix_format_rgba32 = _agg.pix_format_rgba32
pix_format_argb32 = _agg.pix_format_argb32
pix_format_abgr32 = _agg.pix_format_abgr32
pix_format_bgra32 = _agg.pix_format_bgra32
end_of_pix_formats = _agg.end_of_pix_formats
blend_normal = _agg.blend_normal
blend_copy = _agg.blend_copy
end_of_e = _agg.end_of_e
grad_none = _agg.grad_none
grad_linear = _agg.grad_linear
grad_radial = _agg.grad_radial
pad = _agg.pad
reflect = _agg.reflect
repeat = _agg.repeat
user_space = _agg.user_space
object_bounding_box = _agg.object_bounding_box
marker_square = _agg.marker_square
marker_diamond = _agg.marker_diamond
marker_circle = _agg.marker_circle
marker_crossed_circle = _agg.marker_crossed_circle
marker_semiellipse_left = _agg.marker_semiellipse_left
marker_semiellipse_right = _agg.marker_semiellipse_right
marker_semiellipse_up = _agg.marker_semiellipse_up
marker_semiellipse_down = _agg.marker_semiellipse_down
marker_triangle_left = _agg.marker_triangle_left
marker_triangle_right = _agg.marker_triangle_right
marker_triangle_up = _agg.marker_triangle_up
marker_triangle_down = _agg.marker_triangle_down
marker_four_rays = _agg.marker_four_rays
marker_cross = _agg.marker_cross
marker_x = _agg.marker_x
marker_dash = _agg.marker_dash
marker_dot = _agg.marker_dot
marker_pixel = _agg.marker_pixel
end_of_markers = _agg.end_of_markers

from numpy import ndarray

def is_array(obj):
    return type(obj) is ndarray

def is_correct_type(obj, numeric_type):
    return is_array(obj) and (obj.dtype == numeric_type)

def numpy_check(obj, typecode,
                exact_size = [],
                must_be_contiguous = 1,
                allow_coersion = 0):

    if is_correct_type(obj, typecode):
        ary = obj
    elif allow_coersion:
        ary = asarray(obj,typecode)
    else:
        raise TypeError("input is not an array or the array has the wrong type")

    if must_be_contiguous and not ary.flags["CONTIGUOUS"]:
        if allow_coersion:
            ary = ary.copy()
        else:
            raise TypeError("input array must be contiguous")

# check number of dimensions
    required_dims = len(exact_size)
    if required_dims and required_dims != len(ary.shape):
        raise ValueError("The input array does not have the correct shape")

# check exact shape of each dimension
    cnt = 0
    for desired,actual in zip(exact_size,ary.shape):
        if desired != -1 and desired != actual:
            raise ValueError("The %d dimensions of the array has the wrong shape" % (cnt))
        cnt += 1

    return ary


def path_cmd(*args):
    return _agg.path_cmd(*args)

def path_flags(*args):
    return _agg.path_flags(*args)


#----------------------------------------------------------------------------
#
# map strings values to the marker enumerated values and back with:
#   marker_string_map[string] = enum
#   marker_enum_map[enum] = string
#
#----------------------------------------------------------------------------

kiva_marker_to_agg = {}
kiva_marker_to_agg[1] = marker_square
kiva_marker_to_agg[2] = marker_diamond
kiva_marker_to_agg[3] = marker_circle
kiva_marker_to_agg[4] = marker_crossed_circle
kiva_marker_to_agg[5] = marker_x
kiva_marker_to_agg[6] = marker_triangle_up
kiva_marker_to_agg[7] = marker_triangle_down
kiva_marker_to_agg[8] = marker_cross    # "plus" sign; Agg calls this "cross"
kiva_marker_to_agg[9] = marker_dot
kiva_marker_to_agg[10] = marker_pixel


#----------------------------------------------------------------------------
#
# Map strings values to the pix_format enumerated values and back with:
#   pix_format_string_map[string] = enum
#   pix_format_enum_map[enum] = string
#
#----------------------------------------------------------------------------

pix_format_string_map = {}
pix_format_string_map["gray8"] = pix_format_gray8
pix_format_string_map["rgb555"] = pix_format_rgb555
pix_format_string_map["rgb565"] = pix_format_rgb565
pix_format_string_map["rgb24"] = pix_format_rgb24
pix_format_string_map["bgr24"] = pix_format_bgr24
pix_format_string_map["rgba32"] = pix_format_rgba32
pix_format_string_map["argb32"] = pix_format_argb32
pix_format_string_map["abgr32"] = pix_format_abgr32
pix_format_string_map["bgra32"] = pix_format_bgra32

pix_format_enum_map = {}
for key,value in pix_format_string_map.items():
    pix_format_enum_map[value] = key

#----------------------------------------------------------------------------
# Map a pix format string value to the number of bytes per pixel
#----------------------------------------------------------------------------

pix_format_bytes = {}
pix_format_bytes["gray8"] = 1
pix_format_bytes["rgb555"] = 2
pix_format_bytes["rgb565"] = 2
pix_format_bytes["rgb24"] = 3
pix_format_bytes["bgr24"] = 3
pix_format_bytes["rgba32"] = 4
pix_format_bytes["argb32"] = 4
pix_format_bytes["abgr32"] = 4
pix_format_bytes["bgra32"] = 4

pix_format_bits = {}
pix_format_bits["gray8"] = 8
pix_format_bits["rgb555"] = 15
pix_format_bits["rgb565"] = 16
pix_format_bits["rgb24"] = 24
pix_format_bits["bgr24"] = 24
pix_format_bits["rgba32"] = 32
pix_format_bits["argb32"] = 32
pix_format_bits["abgr32"] = 32
pix_format_bits["bgra32"] = 32

#----------------------------------------------------------------------------
#
# Map strings values to the interpolation enumerated values and back with:
#   interp_string_map[string] = enum
#   interp_enum_map[enum] = string
#
#----------------------------------------------------------------------------

interp_string_map = {}
interp_string_map["nearest"] = nearest
interp_string_map["bilinear"] = bilinear
interp_string_map["bicubic"] = bicubic
interp_string_map["spline16"] = spline16
interp_string_map["spline36"] = spline36
interp_string_map["sinc64"] = sinc64
interp_string_map["sinc144"] = sinc144
interp_string_map["sinc256"] = sinc256
interp_string_map["blackman64"] = blackman64
interp_string_map["blackman100"] = blackman100
interp_string_map["blackman256"] = blackman256

interp_enum_map = {}
for key,value in interp_string_map.items():
    interp_enum_map[value] = key


class _Rgba(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    r = property(_agg._Rgba_r_get, _agg._Rgba_r_set)
    g = property(_agg._Rgba_g_get, _agg._Rgba_g_set)
    b = property(_agg._Rgba_b_get, _agg._Rgba_b_set)
    a = property(_agg._Rgba_a_get, _agg._Rgba_a_set)

    def __init__(self, *args):
        _agg._Rgba_swiginit(self, _agg.new__Rgba(*args))

    def gradient(self, *args):
        return _agg._Rgba_gradient(self, *args)

    def premultiply(self, *args):
        return _agg._Rgba_premultiply(self, *args)

    def __repr__(self, *args):
        return _agg._Rgba___repr__(self, *args)

    def __eq__(self, *args):
        return _agg._Rgba___eq__(self, *args)

    def asarray(self, *args):
        return _agg._Rgba_asarray(self, *args)
    __swig_destroy__ = _agg.delete__Rgba

# Register _Rgba in _agg:
_agg._Rgba_swigregister(_Rgba)
cvar = _agg.cvar
pi = cvar.pi


def is_sequence(arg):
    try:
        len(arg)
        return 1
    except:
        return 0

# Use sub-class to allow sequence as input
class Rgba(_Rgba):
    def __init__(self,*args):
        if len(args) == 1 and is_sequence(args[0]):
            args = tuple(args[0])
            if len(args) not in [3,4]:
                raise ValueError("array argument must be 1x3 or 1x4")
        _Rgba.__init__(self,*args)

class AggFontType(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    size = property(_agg.AggFontType_size_get, _agg.AggFontType_size_set)
    name = property(_agg.AggFontType_name_get, _agg.AggFontType_name_set)
    family = property(_agg.AggFontType_family_get, _agg.AggFontType_family_set)
    style = property(_agg.AggFontType_style_get, _agg.AggFontType_style_set)
    encoding = property(_agg.AggFontType_encoding_get, _agg.AggFontType_encoding_set)
    face_index = property(_agg.AggFontType_face_index_get, _agg.AggFontType_face_index_set)
    filename = property(_agg.AggFontType_filename_get, _agg.AggFontType_filename_set)

    def __init__(self, *args):
        _agg.AggFontType_swiginit(self, _agg.new_AggFontType(*args))

    def change_filename(self, *args):
        return _agg.AggFontType_change_filename(self, *args)

    def is_loaded(self, *args):
        return _agg.AggFontType_is_loaded(self, *args)

    def __repr__(self, *args):
        return _agg.AggFontType___repr__(self, *args)

    def __eq__(self, *args):
        return _agg.AggFontType___eq__(self, *args)
    __swig_destroy__ = _agg.delete_AggFontType

# Register AggFontType in _agg:
_agg.AggFontType_swigregister(AggFontType)


def unicode_safe_init(self, _name="Arial", _size=12, _family=0, _style=0,
                      _encoding=0, _face_index=0, validate=True):
### HACK:  C++ stuff expects a string (not unicode) for the face_name, so fix
###        if needed.
### Only for python < 3
    if '' == b'':
        if isinstance(_name, unicode):
            _name = _name.encode("latin1")
    else:
        if isinstance(_name, bytes):
            _name = _name.decode()
    obj = _agg.new_AggFontType(_name, _size, _family, _style,
                               _encoding, _face_index, validate)
    _swig_setattr(self, AggFontType, "this", obj)
    _swig_setattr(self, AggFontType, "thisown", 1)

# This is a crappy way of overriding the constructor
AggFontType.__init__ = unicode_safe_init


def rotation_matrix(*args):
    return _agg.rotation_matrix(*args)

def scaling_matrix(*args):
    return _agg.scaling_matrix(*args)

def translation_matrix(*args):
    return _agg.translation_matrix(*args)

def skewing_matrix(*args):
    return _agg.skewing_matrix(*args)
class _AffineMatrix(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args):
        _agg._AffineMatrix_swiginit(self, _agg.new__AffineMatrix(*args))

    def __invert__(self, *args):
        return _agg._AffineMatrix___invert__(self, *args)

    def reset(self, *args):
        return _agg._AffineMatrix_reset(self, *args)

    def multiply(self, *args):
        return _agg._AffineMatrix_multiply(self, *args)

    def invert(self, *args):
        return _agg._AffineMatrix_invert(self, *args)

    def flip_x(self, *args):
        return _agg._AffineMatrix_flip_x(self, *args)

    def flip_y(self, *args):
        return _agg._AffineMatrix_flip_y(self, *args)

    def scale(self, *args):
        return _agg._AffineMatrix_scale(self, *args)

    def determinant(self, *args):
        return _agg._AffineMatrix_determinant(self, *args)

    def asarray(self, *args):
        return _agg._AffineMatrix_asarray(self, *args)

    def load_from(self, *args):
        return _agg._AffineMatrix_load_from(self, *args)

    def __repr__(self, *args):
        return _agg._AffineMatrix___repr__(self, *args)

    def __getitem__(self, *args):
        return _agg._AffineMatrix___getitem__(self, *args)

    def __eq__(self, *args):
        return _agg._AffineMatrix___eq__(self, *args)
    __swig_destroy__ = _agg.delete__AffineMatrix

# Register _AffineMatrix in _agg:
_agg._AffineMatrix_swigregister(_AffineMatrix)


def is_sequence(arg):
    try:
        len(arg)
        return 1
    except:
        return 0

# AffineMatrix sub-class to get around problems with adding
# a AffineMatrix constructor that accepts a Numeric array
# as input.
class AffineMatrix(_AffineMatrix):
    def __init__(self,*args):
        if len(args) == 1 and is_sequence(args[0]):
            args = tuple(args[0])
            if len(args) != 6:
                raise ValueError("array argument must be 1x6")
        _AffineMatrix.__init__(self,*args)

    def __imul__(self,other):
        """ inplace multiply

            We don't use the C++ version of this because it ends up
            deleting the object out from under itself.
        """
        self.multiply(other)
        return self

class CompiledPath(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")
    __repr__ = _swig_repr

    def __init__(self, *args):
        _agg.CompiledPath_swiginit(self, _agg.new_CompiledPath(*args))

    def remove_all(self, *args):
        return _agg.CompiledPath_remove_all(self, *args)

    def begin_path(self, *args):
        return _agg.CompiledPath_begin_path(self, *args)

    def close_path(self, *args):
        return _agg.CompiledPath_close_path(self, *args)

    def move_to(self, *args):
        return _agg.CompiledPath_move_to(self, *args)

    def line_to(self, *args):
        return _agg.CompiledPath_line_to(self, *args)

    def quad_curve_to(self, *args):
        return _agg.CompiledPath_quad_curve_to(self, *args)

    def curve_to(self, *args):
        return _agg.CompiledPath_curve_to(self, *args)

    def arc(self, *args):
        return _agg.CompiledPath_arc(self, *args)

    def arc_to(self, *args):
        return _agg.CompiledPath_arc_to(self, *args)

    def add_path(self, *args):
        return _agg.CompiledPath_add_path(self, *args)

    def lines(self, *args):
        return _agg.CompiledPath_lines(self, *args)

    def line_set(self, *args):
        return _agg.CompiledPath_line_set(self, *args)

    def rect(self, *args):
        return _agg.CompiledPath_rect(self, *args)

    def rects(self, *args):
        return _agg.CompiledPath_rects(self, *args)

    def translate_ctm(self, *args):
        return _agg.CompiledPath_translate_ctm(self, *args)

    def rotate_ctm(self, *args):
        return _agg.CompiledPath_rotate_ctm(self, *args)

    def scale_ctm(self, *args):
        return _agg.CompiledPath_scale_ctm(self, *args)

    def concat_ctm_agg(self, *args):
        return _agg.CompiledPath_concat_ctm_agg(self, *args)

    def set_ctm_agg(self, *args):
        return _agg.CompiledPath_set_ctm_agg(self, *args)

    def kivaaffine_to_aggaffine(self, ctm):
        return AffineMatrix(ctm[0,0], ctm[0,1], ctm[1,0], ctm[1,1],
                            ctm[2,0], ctm[2,1])
    def concat_ctm(self, ctm):
    # This is really tortured and may cause performance problems.
    # Unfortunately I don't see a much better way right now.
        if '__class__' in dir(ctm) and ctm.__class__.__name__.count('AffineMatrix'):
            self.concat_ctm_agg(ctm)
        else:
            self.concat_ctm_agg(self.kivaaffine_to_aggaffine(ctm))
    def set_ctm(self, ctm):
        if '__class__' in dir(ctm) and ctm.__class__.__name__.count('AffineMatrix'):
            self.set_ctm_agg(ctm)
        else:
            self.set_ctm_agg(self.kivaaffine_to_aggaffine(ctm))


    def get_ctm(self, *args):
        return _agg.CompiledPath_get_ctm(self, *args)

    def save_ctm(self, *args):
        return _agg.CompiledPath_save_ctm(self, *args)

    def restore_ctm(self, *args):
        return _agg.CompiledPath_restore_ctm(self, *args)

    def total_vertices(self, *args):
        return _agg.CompiledPath_total_vertices(self, *args)

    def _rewind(self, *args):
        return _agg.CompiledPath__rewind(self, *args)

    def vertex(self, *args):
        return _agg.CompiledPath_vertex(self, *args)

    def _vertex(self, *args):
        return _agg.CompiledPath__vertex(self, *args)
    __swig_destroy__ = _agg.delete_CompiledPath

# Register CompiledPath in _agg:
_agg.CompiledPath_swigregister(CompiledPath)


from numpy import array, float64
def _vertices(self):
        """ This is only used for testing.  It allows us to retrieve
            all the vertices in the path at once.  The vertices are
            returned as an Nx4 array of the following format.

	        x0, y0, cmd0, flag0
                x1, y1, cmd0, flag1
                ...
        """
        vertices = []
        self._rewind()
        cmd_flag = 1
        while cmd_flag != 0:
            pt, cmd_flag = self._vertex()
            cmd,flag = _agg.path_cmd(cmd_flag),_agg.path_flags(cmd_flag)
            vertices.append((pt[0],pt[1], cmd, flag))        
        return array(vertices)

CompiledPath._vertices = _vertices    


def get_kiva_ctm(self):
        aff = self.get_ctm()
        return array([[aff[0], aff[1], 0],
                      [aff[2], aff[3], 0],
                      [aff[4], aff[5], 1]], float64)

CompiledPath.get_kiva_ctm = get_kiva_ctm



def graphics_context_from_array(*args):
    return _agg.graphics_context_from_array(*args)

def destroy_graphics_context(*args):
    return _agg.destroy_graphics_context(*args)

def graphics_context_multiply_alpha(*args):
    return _agg.graphics_context_multiply_alpha(*args)

        # used in GraphicsContextArray constructors
from numpy import array, asarray, zeros, uint8, frombuffer, shape, ndarray, resize, dtype
import numpy

# Define paths for the two markers that Agg renders incorrectly
from kiva.constants import DIAMOND_MARKER, CIRCLE_MARKER, FILL_STROKE

def circle_marker_path(path, size):
    circle_points = array([[ 1.   ,  0.   ],
                           [ 0.966,  0.259],
                           [ 0.866,  0.5  ],
                           [ 0.707,  0.707],
                           [ 0.5  ,  0.866],
                           [ 0.259,  0.966],
                           [ 0.   ,  1.   ],
                           [-0.259,  0.966],
                           [-0.5  ,  0.866],
                           [-0.707,  0.707],
                           [-0.866,  0.5  ],
                           [-0.966,  0.259],
                           [-1.   ,  0.   ],
                           [-0.966, -0.259],
                           [-0.866, -0.5  ],
                           [-0.707, -0.707],
                           [-0.5  , -0.866],
                           [-0.259, -0.966],
                           [ 0.   , -1.   ],
                           [ 0.259, -0.966],
                           [ 0.5  , -0.866],
                           [ 0.707, -0.707],
                           [ 0.866, -0.5  ],
                           [ 0.966, -0.259],
                           [ 1.   , 0.    ]])
    if size <= 5:
        pts = circle_points[::3] * size
    elif size <= 10:
        pts = circle_points[::2] * size
    else:
        pts = circle_points * size
    path.lines(pts)

substitute_markers = {
    CIRCLE_MARKER: (circle_marker_path, FILL_STROKE)
}

# global freetype engine for text rendering.
#from enthought import freetype
#ft_engine = freetype.FreeType(dpi=120.0)

from kiva import fonttools

def handle_unicode(text):
    "Returns a utf8 encoded 8-bit string from 'text'"
# For now we just deal with unicode by converting to utf8
# Later we can add full-blown support with wchar_t/Py_UNICODE
# typemaps etc.
    try:
        if '' == b'' and isinstance(text, unicode):
            text = text.encode("utf8")
        return text
    except:
        raise UnicodeError("Error encoding text to utf8.")


def cleanup_font_threading_primitives(*args):
    return _agg.cleanup_font_threading_primitives(*args)

        # Register module function to clean up mutexes and criticalsection
        # objects when the process quits.

import atexit
atexit.register(cleanup_font_threading_primitives)


class GraphicsContextArray(object):
    thisown = property(lambda x: x.this.own(), lambda x, v: x.this.own(v), doc="The membership flag")

    def __init__(self, *args, **kwargs):
        raise AttributeError("No constructor defined")
    __repr__ = _swig_repr

                # We define our own constructor AND destructor.
    def __init__(self, ary_or_size, pix_format="bgra32",
                 interpolation="nearest", base_pixel_scale=1.0,
                 bottom_up=1):
        """ When specifying size, it must be a two element tuple.
            Array input is always treated as an image.

            This class handles the polymorphism of the underlying
            template classes for individual pixel formats.
        """

        pix_format_id = pix_format_string_map[pix_format]
        img_depth = pix_format_bytes[pix_format]
        interpolation_id = interp_string_map[interpolation]
        if type(ary_or_size) is tuple:
            width, height = ary_or_size
    # Ensure that we pass on integers.
            width = int(width)
            height = int(height)
            ary = zeros((height, width, img_depth), uint8)
            ary[:] = 255
        else:
            ary = ary_or_size
            sh = shape(ary)
            if len(sh) == 2:
                if img_depth != 1:
                    msg = "2D arrays must use a format that is one byte per pixel"
                    raise ValueError(msg)
            elif len(sh) == 3:
                if img_depth != sh[2]:
                    msg = "Image depth and format are incompatible"
                    raise ValueError(msg)
            else:
                msg = "only 2 or 3 dimensional arrays are supported as images"
                msg += " but got sh=%r" % (sh,)
                raise TypeError(msg)
            msg = "Only UnsignedInt8 arrays are supported but got "
            assert ary.dtype == dtype('uint8'), msg + repr(ary.dtype)

        if cvar.ALWAYS_32BIT_WORKAROUND_FLAG:
            if ary.shape[-1] == 3:
                if pix_format not in ('rgb24', 'bgr24'):
                    import warnings
                    warnings.warn('need to workaround AGG bug since '
                            'ALWAYS_32BIT_WORKAROUND is on, but got unhandled '
                            'format %r' % pix_format)
                else:
                    pix_format = '%sa32' % pix_format[:3]
                    ary = numpy.dstack([ary, numpy.empty(ary.shape[:2], dtype=uint8)])
                    ary[:,:,-1].fill(255)
            pix_format_id = pix_format_string_map[pix_format]
            img_depth = pix_format_bytes[pix_format]

        obj = graphics_context_from_array(ary,pix_format_id,interpolation_id,
                                          bottom_up)

    # Apply base scale for a HiDPI context
        _agg.GraphicsContextArray_scale_ctm(obj, base_pixel_scale, base_pixel_scale)

        _swig_setattr(self, GraphicsContextArray, 'this', obj)
    # swig 1.3.28 does not have real thisown, thisown is mapped
    # to this.own() but with previous 'self.this=obj' an
    # attribute 'own' error is raised. Does this workaround
    # work with pre-1.3.28 swig?
        _swig_setattr(self, GraphicsContextArray, 'thisown2', 1)

        self.bmp_array = ary
        self.base_scale = base_pixel_scale

    def __del__(self, destroy=_agg.destroy_graphics_context):
        try:
            if self.thisown2: destroy(self)
        except: pass



    def bottom_up(self, *args):
        return _agg.GraphicsContextArray_bottom_up(self, *args)

    def width(self, *args):
        return _agg.GraphicsContextArray_width(self, *args)

    def height(self, *args):
        return _agg.GraphicsContextArray_height(self, *args)

    def stride(self, *args):
        return _agg.GraphicsContextArray_stride(self, *args)

    def format(self):
        enum = _agg.GraphicsContextArray_format(self)
        return pix_format_enum_map[enum]



    def get_image_interpolation(self):
        enum = _agg.GraphicsContextArray_get_image_interpolation(self)
        return interp_enum_map[enum]



    def set_image_interpolation(self,interp):
        enum = interp_string_map[interp]
        _agg.GraphicsContextArray_set_image_interpolation(self,enum)



    def set_stroke_color(self,color):
        if is_array(color) and len(color) == 3:
            ary = color
            r,g,b = ary
            color = Rgba(r,g,b)
        elif is_array(color) and len(color) == 4:
            ary = color
            r,g,b,a = ary
            color = Rgba(r,g,b,a)
        _agg.GraphicsContextArray_set_stroke_color(self,color)



    def get_stroke_color(self, *args):
        return _agg.GraphicsContextArray_get_stroke_color(self, *args)

    def set_line_width(self, *args):
        return _agg.GraphicsContextArray_set_line_width(self, *args)

    def set_line_join(self, *args):
        return _agg.GraphicsContextArray_set_line_join(self, *args)

    def set_line_cap(self, *args):
        return _agg.GraphicsContextArray_set_line_cap(self, *args)

    def set_line_dash(self, *args):
        return _agg.GraphicsContextArray_set_line_dash(self, *args)

    def set_blend_mode(self, *args):
        return _agg.GraphicsContextArray_set_blend_mode(self, *args)

    def get_blend_mode(self, *args):
        return _agg.GraphicsContextArray_get_blend_mode(self, *args)

    def set_fill_color(self,color):
        if is_array(color) and len(color) == 3:
            ary = color
            r,g,b = ary
            color = Rgba(r,g,b)
        elif is_array(color) and len(color) == 4:
            ary = color
            r,g,b,a = ary
            color = Rgba(r,g,b,a)
        _agg.GraphicsContextArray_set_fill_color(self,color)



    def get_fill_color(self, *args):
        return _agg.GraphicsContextArray_get_fill_color(self, *args)

    def set_alpha(self, *args):
        return _agg.GraphicsContextArray_set_alpha(self, *args)

    def get_alpha(self, *args):
        return _agg.GraphicsContextArray_get_alpha(self, *args)

    def set_antialias(self, *args):
        return _agg.GraphicsContextArray_set_antialias(self, *args)

    def get_antialias(self, *args):
        return _agg.GraphicsContextArray_get_antialias(self, *args)

    def set_miter_limit(self, *args):
        return _agg.GraphicsContextArray_set_miter_limit(self, *args)

    def set_flatness(self, *args):
        return _agg.GraphicsContextArray_set_flatness(self, *args)

    def set_text_position(self, *args):
        return _agg.GraphicsContextArray_set_text_position(self, *args)

    def get_text_position(self, *args):
        return _agg.GraphicsContextArray_get_text_position(self, *args)

    def show_text_simple(self, *args):
        return _agg.GraphicsContextArray_show_text_simple(self, *args)

    def show_text_at_point(self, text, dx, dy):
        text = handle_unicode(text)
        return _agg.GraphicsContextArray_show_text_at_point(self, text, dx, dy)



    def show_text(self, text, point = None):
        """Displays text at point, or at the current text pen position
           if point is None.  Returns true if text displayed properly,
           false if there was a font issue or a glyph could not be
           rendered.  Will handle multi-line text separated by backslash-ns"""

        text = handle_unicode(text)

        linelist = text.split('\n')

        if point:
            savepoint = self.get_text_position()
            self.set_text_position(*point)
        orig_tm = self.get_text_matrix()
        next_tm = orig_tm
        success = True
        for line in linelist:
            self.set_text_matrix(next_tm)
            success = success and self.show_text_simple(line)
            extent = self.get_text_extent(line)
            txt_xlat = translation_matrix(0,(extent[1]-extent[3])*1.4)
            txt_xlat.multiply(next_tm)
            next_tm = txt_xlat

        if point:
            self.set_text_position(*savepoint)
        if not success:
            raise RuntimeError("Font not loaded/initialized.")



    def get_text_extent(self, text):
        if not self.is_font_initialized():
            raise RuntimeError("Font not loaded/initialized.")
        else:
            text = handle_unicode(text)
            return _agg.GraphicsContextArray_get_text_extent(self, text)



    def is_font_initialized(self, *args):
        return _agg.GraphicsContextArray_is_font_initialized(self, *args)

    def set_text_matrix(self, matrix):
        """ Set the text matrix.

        `matrix` must be either a kiva.agg.AffineMatrix instance, or
        a 3x3 numpy array.
        """
        if isinstance(matrix, ndarray) and matrix.shape == (3,3):
            matrix = AffineMatrix(matrix[0, 0], matrix[0, 1],
                                  matrix[1, 0], matrix[1, 1],
                                  matrix[2, 0], matrix[2, 1])
        _agg.GraphicsContextArray_set_text_matrix(self, matrix)



    def get_text_matrix(self, *args):
        return _agg.GraphicsContextArray_get_text_matrix(self, *args)

    def set_character_spacing(self, *args):
        return _agg.GraphicsContextArray_set_character_spacing(self, *args)

    def get_character_spacing(self, *args):
        return _agg.GraphicsContextArray_get_character_spacing(self, *args)

    def set_text_drawing_mode(self, *args):
        return _agg.GraphicsContextArray_set_text_drawing_mode(self, *args)

                # backward compatibility
                # Also, Enable calls get_full_text_extent exclusively; it expects the returned
                # arguments to be in a different order
    def get_full_text_extent(self, text):
        leading, descent, w, h = self.get_text_extent(text)
        return (w, h, descent, leading)


    def set_font(self, font):
        retval = False
        if isinstance(font, AggFontType):
            agg_font = font
        elif isinstance(font, fonttools.Font):
            cur_font = self.get_font()
            if cur_font.is_loaded() and (font.face_name == cur_font.name) and \
                (font.size == cur_font.size) and (font.style == cur_font.style) \
                and (font.encoding == cur_font.encoding):
                return
            else:
                spec = font.findfont()
                agg_font = AggFontType(font.face_name, font.size, font.family, font.style,
                                       font.encoding, spec.face_index, False)
                agg_font.filename = spec.filename
        else:
    # XXX: What are we expecting here?
            agg_font = AggFontType(font.face_name, font.size, font.family, font.style, font.encoding)
        try:
            retval = _agg.GraphicsContextArray_set_font(self, agg_font)
            if not retval:
                raise RuntimeError("Unable to load font.")
        except:
            raise RuntimeError("Unable to load font.")



    def set_font_size(self, size):
        if not _agg.GraphicsContextArray_set_font_size(self, size):
            raise RuntimeError("Font not loaded/initialized.")



    def get_font(self, *args):
        return _agg.GraphicsContextArray_get_font(self, *args)

    def save_state(self, *args):
        return _agg.GraphicsContextArray_save_state(self, *args)

    def restore_state(self, *args):
        return _agg.GraphicsContextArray_restore_state(self, *args)

    def translate_ctm(self, *args):
        return _agg.GraphicsContextArray_translate_ctm(self, *args)

    def rotate_ctm(self, *args):
        return _agg.GraphicsContextArray_rotate_ctm(self, *args)

    def scale_ctm(self, *args):
        return _agg.GraphicsContextArray_scale_ctm(self, *args)

    def concat_ctm(self, m):
        if isinstance(m, tuple):
            _agg.GraphicsContextArray_concat_ctm(self, _AffineMatrix(*m))
        else:
            _agg.GraphicsContextArray_concat_ctm(self, m)



    def set_ctm(self, m):
        if isinstance(m, tuple):
            _agg.GraphicsContextArray_set_ctm(self, _AffineMatrix(*m))
        else:
            _agg.GraphicsContextArray_set_ctm(self, m)



    def get_ctm(self):
        tmp = _agg.GraphicsContextArray_get_ctm(self)
        return (tmp[0], tmp[1], tmp[2], tmp[3], tmp[4], tmp[5])



    def get_freetype_text_matrix(self, *args):
        return _agg.GraphicsContextArray_get_freetype_text_matrix(self, *args)

    def flush(self, *args):
        return _agg.GraphicsContextArray_flush(self, *args)

    def synchronize(self, *args):
        return _agg.GraphicsContextArray_synchronize(self, *args)

    def begin_page(self, *args):
        return _agg.GraphicsContextArray_begin_page(self, *args)

    def end_page(self, *args):
        return _agg.GraphicsContextArray_end_page(self, *args)

    def begin_path(self, *args):
        return _agg.GraphicsContextArray_begin_path(self, *args)

    def move_to(self, *args):
        return _agg.GraphicsContextArray_move_to(self, *args)

    def line_to(self, *args):
        return _agg.GraphicsContextArray_line_to(self, *args)

    def curve_to(self, *args):
        return _agg.GraphicsContextArray_curve_to(self, *args)

    def quad_curve_to(self, *args):
        return _agg.GraphicsContextArray_quad_curve_to(self, *args)

    def arc(self, *args):
        return _agg.GraphicsContextArray_arc(self, *args)

    def arc_to(self, *args):
        return _agg.GraphicsContextArray_arc_to(self, *args)

    def close_path(self, *args):
        return _agg.GraphicsContextArray_close_path(self, *args)

    def add_path(self, *args):
        return _agg.GraphicsContextArray_add_path(self, *args)

    def lines(self, *args):
        return _agg.GraphicsContextArray_lines(self, *args)

    def line_set(self, *args):
        return _agg.GraphicsContextArray_line_set(self, *args)

    def rect(self, *args):
        return _agg.GraphicsContextArray_rect(self, *args)

    def rects(self, *args):
        return _agg.GraphicsContextArray_rects(self, *args)

    def _get_path(self, *args):
        return _agg.GraphicsContextArray__get_path(self, *args)

    def clip(self, *args):
        return _agg.GraphicsContextArray_clip(self, *args)

    def even_odd_clip(self, *args):
        return _agg.GraphicsContextArray_even_odd_clip(self, *args)

    def get_num_clip_regions(self, *args):
        return _agg.GraphicsContextArray_get_num_clip_regions(self, *args)

    def get_clip_region(self, *args):
        return _agg.GraphicsContextArray_get_clip_region(self, *args)

    def clip_to_rect(self, *args):
        return _agg.GraphicsContextArray_clip_to_rect(self, *args)

    def clip_to_rects(self, *args):
        return _agg.GraphicsContextArray_clip_to_rects(self, *args)

    def clear_clip_path(self, *args):
        return _agg.GraphicsContextArray_clear_clip_path(self, *args)

    def clear(self, *args):
        return _agg.GraphicsContextArray_clear(self, *args)

    def stroke_path(self, *args):
        return _agg.GraphicsContextArray_stroke_path(self, *args)

    def fill_path(self, *args):
        return _agg.GraphicsContextArray_fill_path(self, *args)

    def eof_fill_path(self, *args):
        return _agg.GraphicsContextArray_eof_fill_path(self, *args)

    def draw_path(self, *args):
        return _agg.GraphicsContextArray_draw_path(self, *args)

    def draw_rect(self, *args):
        return _agg.GraphicsContextArray_draw_rect(self, *args)

    def draw_image(self, img, rect=None, force_copy=False):
        from PIL import Image

        pil_format_map = {
            "RGB": "rgb24",
            "RGBA": "rgba32",
        }

    # The C++ implementation only handles other
    # GraphicsContexts, so create one.
        if isinstance(img, ndarray):
    # Let PIL figure out the pixel format
            try:
                img = Image.fromarray(img)
            except TypeError as ex:
    # External code is expecting a ValueError
                raise ValueError(str(ex))
        if isinstance(img, Image.Image):
            if img.mode not in pil_format_map:
                img = img.convert("RGB")
            pix_format = pil_format_map[img.mode]
            img = GraphicsContextArray(array(img), pix_format=pix_format)

        if rect is None:
            rect = array((0, 0, img.width(), img.height()), float)

        return _agg.GraphicsContextArray_draw_image(self, img, rect, force_copy)



    def draw_marker_at_points(self, pts, size, kiva_marker_type):
        marker = kiva_marker_to_agg.get(kiva_marker_type, None)
        if marker is None:
            success = 0
        elif kiva_marker_type in (CIRCLE_MARKER,):
    # The kiva circle marker is rather jagged so lets
    # use our own
            path_func, mode = substitute_markers[kiva_marker_type]
            path = self.get_empty_path()
            path_func(path, size)
            success = _agg.GraphicsContextArray_draw_path_at_points(self, pts, path, mode)
        else:
            args = (self,pts,int(size),marker)
            success = _agg.GraphicsContextArray_draw_marker_at_points(self, pts,
                            int(size), marker)
        return success



    def draw_path_at_points(self, *args):
        return _agg.GraphicsContextArray_draw_path_at_points(self, *args)

    def convert_pixel_format(self,pix_format,inplace=0):
        """ Convert gc from one pixel format to another.

            !! This used to be done in C++ code, but difficult-to-find
            !! memory bugs pushed toward a simpler solution.
            !! HACK
            !! Now we just draw into a new gc and assume its underlying C++
            !! object. We must be careful not to add any attributes in the
            !! Python GraphicsContextArray constructor other than the bmp_array.
            !! if we do, we need to copy them here also.
        """
    # make sure it uses sub-class if needed
        new_img = self.__class__((self.width(),self.height()),
                                  pix_format=pix_format,
                                  interpolation=self.get_image_interpolation(),
                                  bottom_up = self.bottom_up())
        new_img.draw_image(self)

        if inplace:
            """
    # swap internals with new_self -- it will dealloc our (now unused) C++
    # object and we'll acquire its new one.  We also get a ref to his bmp_array
            """
            old_this = self.this
            self.this = new_img.this
            new_img.this = old_this
            self.bmp_array = new_img.bmp_array
            return self
        else:
            return new_img

    def get_empty_path(self):
        return CompiledPath()

    def to_image(self):
        """ Return the contents of the GraphicsContext as a PIL Image.

        Images are in RGB or RGBA format; if this GC is not in one of
        these formats, it is automatically converted.

        Returns
        -------
        img : Image
            The contents of the context as a PIL/Pillow Image.
        """
        from PIL import Image
        size = (self.width(), self.height())
        fmt = self.format()

    # determine the output pixel format and PIL format
        if fmt.endswith("32"):
            pilformat = "RGBA"
            pixelformat = "rgba32"
        elif fmt.endswith("24"):
            pilformat = "RGB"
            pixelformat = "rgb24"

    # perform a conversion if necessary
        if fmt != pixelformat:
            newimg = GraphicsContextArray(size, fmt)
            newimg.draw_image(self)
            newimg.convert_pixel_format(pixelformat, 1)
            bmp = newimg.bmp_array
        else:
            bmp = self.bmp_array

        return Image.fromarray(bmp, pilformat)

    def save(self, filename, file_format=None, pil_options=None):
        """ Save the GraphicsContext to a file.  Output files are always
            saved in RGB or RGBA format; if this GC is not in one of
            these formats, it is automatically converted.

            If filename includes an extension, the image format is
            inferred from it.  file_format is only required if the
            format can't be inferred from the filename (e.g. if you
            wanted to save a PNG file as a .dat or .bin).

            filename may also be "file-like" object such as a
            StringIO, in which case a file_format must be supplied

            pil_options is a dict of format-specific options that
            are passed down to the PIL image file writer.  If a writer
            doesn't recognize an option, it is silently ignored.

            If the image has an alpha channel and the specified output
            file format does not support alpha, the image is saved in
            rgb24 format.
        """
        from PIL import Image

        FmtsWithDpi = ('jpg', 'png', 'tiff', 'jpeg')
        FmtsWithoutAlpha = ('jpg', 'bmp', 'eps', "jpeg")
        size = (self.width(), self.height())
        fmt = self.format()

        if pil_options is None:
            pil_options = {}

        file_ext = filename.rpartition(".")[-1].lower() if isinstance(filename, str) else ""
        if (file_ext in FmtsWithDpi or
                (file_format is not None and
                 file_format.lower() in FmtsWithDpi)):
    # Assume 72dpi is 1x
            dpi = int(72 * self.base_scale)
            pil_options["dpi"] = (dpi, dpi)

    # determine the output pixel format and PIL format
        if fmt.endswith("32"):
            pilformat = "RGBA"
            pixelformat = "rgba32"
            if file_ext in FmtsWithoutAlpha or \
               (file_format is not None and file_format.lower() in FmtsWithoutAlpha):
                pilformat = "RGB"
                pixelformat = "rgb24"
        elif fmt.endswith("24"):
            pilformat = "RGB"
            pixelformat = "rgb24"

    # perform a conversion if necessary
        if fmt != pixelformat:
            newimg = GraphicsContextArray(size, fmt)
            newimg.draw_image(self)
            newimg.convert_pixel_format(pixelformat, 1)
            bmp = newimg.bmp_array
        else:
            bmp = self.bmp_array

        img = Image.fromarray(bmp, pilformat)
        img.save(filename, format=file_format, **pil_options)


    #----------------------------------------------------------------
    # context manager interface
    #----------------------------------------------------------------

    def __enter__(self):
        self.save_state()

    def __exit__(self, type, value, traceback):
        self.restore_state()

    #----------------------------------------------------------------
    # IPython/Jupyter support
    #----------------------------------------------------------------

    def _repr_png_(self):
        """ Return a the current contents of the context as PNG image.

        This provides Jupyter and IPython compatibility, so that the graphics
        context can be displayed in the Jupyter Notebook or the IPython Qt
        console.

        Returns
        -------
        data : bytes
            The contents of the context as PNG-format bytes.
        """
        from io import BytesIO

        img = self.to_image()
        data = BytesIO()
        img.save(data, format='png')
        return data.getvalue()



    def linear_gradient(self, *args):
        return _agg.GraphicsContextArray_linear_gradient(self, *args)

    def radial_gradient(self, *args):
        return _agg.GraphicsContextArray_radial_gradient(self, *args)

# Register GraphicsContextArray in _agg:
_agg.GraphicsContextArray_swigregister(GraphicsContextArray)



pil_format_map = {}
pil_format_map["RGB"] = "rgb24"
pil_format_map["RGBA"] = "rgba32"

pil_depth_map = {}
pil_depth_map["RGB"] = 3
pil_depth_map["RGBA"] = 4

class Image(GraphicsContextArray):
    """ Image is a GraphicsContextArray sub-class created from an image file.
    """
    def __init__(self, file, interpolation="nearest", bottom_up=1):
        """ Create an Image object (GraphicsContextArray) from a file.

        Parameters
        ----------
        file
            can be either a file name or an open file object
        interpolation
            specifies the type of filter used when putting the image into
            another GraphicsContextArray
        """
# read the file using PIL
        from PIL import Image as PilImage

        pil_img = PilImage.open(file)

# Convert image to a numpy array
        if (pil_img.mode not in ["RGB","RGBA"] or
            (cvar.ALWAYS_32BIT_WORKAROUND_FLAG and pil_img.mode != "RGBA")):
            pil_img = pil_img.convert(mode="RGBA")

        depth = pil_depth_map[pil_img.mode]
        format = pil_format_map[pil_img.mode]
        img = asarray(pil_img)

        GraphicsContextArray.__init__(self, img, pix_format=format,
                                      interpolation=interpolation,
                                      bottom_up = bottom_up)

    def convert_pixel_format(self,pix_format,inplace=0):
        "Convert gc from one pixel format to another."
# We override the one in the base GraphicsContextArray because that
# one calls our __init__, which is not really the behavior we want.
#
# This problem can be avoided altogether down the road when the
# Image subclass is turned into a factory function.
        new_img = GraphicsContextArray((self.width(),self.height()),
                                  pix_format=pix_format,
                                  interpolation=self.get_image_interpolation(),
                                  bottom_up = self.bottom_up())
        new_img.draw_image(self)

        if inplace:
            old_this = self.this
            self.this = new_img.this
            new_img.this = old_this
            self.bmp_array = new_img.bmp_array
            return self
        else:
            return new_img