Permalink
Browse files

Changes backends to support of independent face and edge alphas

Specifically, alters the base, AGG, PDF, PGF, SVG, Cairo, and Mac OS X
backends to better enable the use of RGBA color values for both fills
and edges. An explicit alpha attribute, if set, will override the
alpha channels of the color values.

Updates test results, which are now what would be expected.

Also fixes a couple bugs with handling of linestyles.
  • Loading branch information...
1 parent 1aefc52 commit 6cc8aaa3e2a493a8df72cc10a08c2422ecb37ae2 @Westacular committed Apr 24, 2013
@@ -362,8 +362,6 @@ def _iter_collection(self, gc, master_transform, all_transforms,
gc0 = self.new_gc()
gc0.copy_properties(gc)
- original_alpha = gc.get_alpha()
-
if Nfacecolors == 0:
rgbFace = None
@@ -387,7 +385,6 @@ def _iter_collection(self, gc, master_transform, all_transforms,
yo = -(yp - yo)
if not (np.isfinite(xo) and np.isfinite(yo)):
continue
- gc0.set_alpha(original_alpha)
if Nfacecolors:
rgbFace = facecolors[i % Nfacecolors]
if Nedgecolors:
@@ -400,16 +397,12 @@ def _iter_collection(self, gc, master_transform, all_transforms,
if fg[3] == 0.0:
gc0.set_linewidth(0)
else:
- gc0.set_alpha(gc0.get_alpha() * fg[3])
- gc0.set_foreground(fg[:3])
+ gc0.set_foreground(fg)
else:
gc0.set_foreground(fg)
if rgbFace is not None and len(rgbFace) == 4:
if rgbFace[3] == 0:
rgbFace = None
- else:
- gc0.set_alpha(gc0.get_alpha() * rgbFace[3])
- rgbFace = rgbFace[:3]
gc0.set_antialiased(antialiaseds[i % Naa])
if Nurls:
gc0.set_url(urls[i % Nurls])
@@ -562,7 +555,7 @@ def _draw_text_as_path(self, gc, x, y, s, prop, angle, ismath):
path, transform = self._get_text_path_transform(
x, y, s, prop, angle, ismath)
- color = gc.get_rgb()[:3]
+ color = gc.get_rgb()
gc.set_linewidth(0.0)
self.draw_path(gc, path, transform, rgbFace=color)
@@ -702,7 +695,8 @@ def __init__(self):
self._joinstyle = 'round'
self._linestyle = 'solid'
self._linewidth = 1
- self._rgb = (0.0, 0.0, 0.0)
+ self._rgb = (0.0, 0.0, 0.0, 1.0)
+ self._orig_color = (0.0, 0.0, 0.0, 1.0)
self._hatch = None
self._url = None
self._gid = None
@@ -711,6 +705,7 @@ def __init__(self):
def copy_properties(self, gc):
'Copy properties from gc to self'
self._alpha = gc._alpha
+ self._forced_alpha = gc._forced_alpha
self._antialiased = gc._antialiased
self._capstyle = gc._capstyle
self._cliprect = gc._cliprect
@@ -720,6 +715,7 @@ def copy_properties(self, gc):
self._linestyle = gc._linestyle
self._linewidth = gc._linewidth
self._rgb = gc._rgb
+ self._orig_color = gc._orig_color
self._hatch = gc._hatch
self._url = gc._url
self._gid = gc._gid
@@ -781,6 +777,13 @@ def get_dashes(self):
"""
return self._dashes
+ def get_forced_alpha(self):
+ """
+ Return whether the value given by get_alpha() should be used to
+ override any other alpha-channel values.
+ """
+ return self._forced_alpha
+
def get_joinstyle(self):
"""
Return the line join style as one of ('miter', 'round', 'bevel')
@@ -840,7 +843,9 @@ def set_alpha(self, alpha):
self._alpha = alpha
self._forced_alpha = True
else:
+ self._alpha = 1.0
self._forced_alpha = False
+ self.set_foreground(self._orig_color)
def set_antialiased(self, b):
"""
@@ -890,30 +895,29 @@ def set_dashes(self, dash_offset, dash_list):
"""
self._dashes = dash_offset, dash_list
- def set_foreground(self, fg, isRGB=False):
+ def set_foreground(self, fg, isRGBA=False):
"""
Set the foreground color. fg can be a MATLAB format string, a
html hex color string, an rgb or rgba unit tuple, or a float between 0
and 1. In the latter case, grayscale is used.
- If you know fg is rgb or rgba, set ``isRGB=True`` for
+ If you know fg is rgb or rgba, set ``isRGBA=True`` for
efficiency.
"""
- if isRGB:
+ self._orig_color = fg
+ if self._forced_alpha:
+ self._rgb = colors.colorConverter.to_rgba(fg, self._alpha)
+ elif isRGBA:
self._rgb = fg
else:
self._rgb = colors.colorConverter.to_rgba(fg)
- if len(self._rgb) == 4 and not self._forced_alpha:
- self.set_alpha(self._rgb[3])
- # Use set_alpha method here so that subclasses will
- # be calling their own version, which may set their
- # own attributes.
def set_graylevel(self, frac):
"""
Set the foreground color to be a gray level with *frac*
"""
- self._rgb = (frac, frac, frac)
+ self._orig_color = frac
+ self._rgb = (frac, frac, frac, self._alpha)
def set_joinstyle(self, js):
"""
@@ -110,13 +110,13 @@ def set_width_height(self, width, height):
# font transform?
- def _fill_and_stroke (self, ctx, fill_c, alpha):
+ def _fill_and_stroke (self, ctx, fill_c, alpha, alpha_overrides):
if fill_c is not None:
ctx.save()
- if len(fill_c) == 3:
+ if len(fill_c) == 3 or alpha_overrides:
ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], alpha)
else:
- ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], alpha*fill_c[3])
+ ctx.set_source_rgba (fill_c[0], fill_c[1], fill_c[2], fill_c[3])
ctx.fill_preserve()
ctx.restore()
ctx.stroke()
@@ -150,7 +150,7 @@ def draw_path(self, gc, path, transform, rgbFace=None):
ctx.new_path()
self.convert_path(ctx, path, transform)
- self._fill_and_stroke(ctx, rgbFace, gc.get_alpha())
+ self._fill_and_stroke(ctx, rgbFace, gc.get_alpha(), gc.get_forced_alpha())
def draw_image(self, gc, x, y, im):
# bbox - not currently used
@@ -316,7 +316,10 @@ def set_alpha(self, alpha):
GraphicsContextBase.set_alpha(self, alpha)
_alpha = self.get_alpha()
rgb = self._rgb
- self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], _alpha)
+ if self.get_forced_alpha():
+ self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], _alpha)
+ else:
+ self.ctx.set_source_rgba (rgb[0], rgb[1], rgb[2], rgb[3])
#def set_antialiased(self, b):
@@ -359,8 +362,8 @@ def set_dashes(self, offset, dashes):
self.renderer.points_to_pixels (np.asarray(dashes)), offset)
- def set_foreground(self, fg, isRGB=None):
- GraphicsContextBase.set_foreground(self, fg, isRGB)
+ def set_foreground(self, fg, isRGBA=None):
+ GraphicsContextBase.set_foreground(self, fg, isRGBA)
if len(self._rgb) == 3:
self.ctx.set_source_rgb(*self._rgb)
else:
@@ -393,8 +393,8 @@ def set_dashes(self, dash_offset, dash_list):
self.gdkGC.line_style = gdk.LINE_ON_OFF_DASH
- def set_foreground(self, fg, isRGB=False):
- GraphicsContextBase.set_foreground(self, fg, isRGB)
+ def set_foreground(self, fg, isRGBA=False):
+ GraphicsContextBase.set_foreground(self, fg, isRGBA)
self.gdkGC.foreground = self.rgb_to_gdk_color(self.get_rgb())
@@ -50,13 +50,13 @@ def set_width_height (self, width, height):
def draw_path(self, gc, path, transform, rgbFace=None):
if rgbFace is not None:
- rgbFace = tuple(rgbFace[:3])
+ rgbFace = tuple(rgbFace)
linewidth = gc.get_linewidth()
gc.draw_path(path, transform, linewidth, rgbFace)
def draw_markers(self, gc, marker_path, marker_trans, path, trans, rgbFace=None):
if rgbFace is not None:
- rgbFace = tuple(rgbFace[:3])
+ rgbFace = tuple(rgbFace)
linewidth = gc.get_linewidth()
gc.draw_markers(marker_path, marker_trans, path, trans, linewidth, rgbFace)
@@ -183,12 +183,14 @@ def __init__(self):
def set_alpha(self, alpha):
GraphicsContextBase.set_alpha(self, alpha)
_alpha = self.get_alpha()
- _macosx.GraphicsContext.set_alpha(self, _alpha)
+ _macosx.GraphicsContext.set_alpha(self, _alpha, self.get_forced_alpha())
+ rgb = self.get_rgb()
+ _macosx.GraphicsContext.set_foreground(self, rgb)
- def set_foreground(self, fg, isRGB=False):
- GraphicsContextBase.set_foreground(self, fg, isRGB)
+ def set_foreground(self, fg, isRGBA=False):
+ GraphicsContextBase.set_foreground(self, fg, isRGBA)
rgb = self.get_rgb()
- _macosx.GraphicsContext.set_foreground(self, rgb[:3])
+ _macosx.GraphicsContext.set_foreground(self, rgb)
def set_graylevel(self, fg):
GraphicsContextBase.set_graylevel(self, fg)
@@ -1064,7 +1064,7 @@ def alphaState(self, alpha):
self.nextAlphaState += 1
self.alphaStates[alpha] = \
(name, { 'Type': Name('ExtGState'),
- 'CA': alpha, 'ca': alpha })
+ 'CA': alpha[0], 'ca': alpha[1] })
return name
def hatchPattern(self, hatch_style):
@@ -1443,11 +1443,21 @@ def check_gc(self, gc, fillcolor=None):
orig_fill = gc._fillcolor
gc._fillcolor = fillcolor
+ orig_alphas = gc._effective_alphas
+
+ if gc._forced_alpha:
+ gc._effective_alphas = (gc._alpha, gc._alpha)
+ elif fillcolor is None or len(fillcolor) < 4:
+ gc._effective_alphas = (gc._rgb[3], 1.0)
+ else:
+ gc._effective_alphas = (gc._rgb[3], fillcolor[3])
+
delta = self.gc.delta(gc)
if delta: self.file.output(*delta)
# Restore gc to avoid unwanted side effects
gc._fillcolor = orig_fill
+ gc._effective_alphas = orig_alphas
def tex_font_mapping(self, texfont):
if self.tex_font_map is None:
@@ -2004,6 +2014,7 @@ class GraphicsContextPdf(GraphicsContextBase):
def __init__(self, file):
GraphicsContextBase.__init__(self)
self._fillcolor = (0.0, 0.0, 0.0)
+ self._effective_alphas = (1.0, 1.0)
self.file = file
self.parent = None
@@ -2072,8 +2083,8 @@ def dash_cmd(self, dashes):
offset = 0
return [list(dash), offset, Op.setdash]
- def alpha_cmd(self, alpha):
- name = self.file.alphaState(alpha)
+ def alpha_cmd(self, alpha, forced, effective_alphas):
+ name = self.file.alphaState(effective_alphas)
return [name, Op.setgstate]
def hatch_cmd(self, hatch):
@@ -2138,7 +2149,7 @@ def clip_cmd(self, cliprect, clippath):
commands = (
(('_cliprect', '_clippath'), clip_cmd), # must come first since may pop
- (('_alpha',), alpha_cmd),
+ (('_alpha', '_forced_alpha', '_effective_alphas'), alpha_cmd),
(('_capstyle',), capstyle_cmd),
(('_fillcolor',), fillcolor_cmd),
(('_joinstyle',), joinstyle_cmd),
@@ -2183,6 +2194,7 @@ def copy_properties(self, other):
"""
GraphicsContextBase.copy_properties(self, other)
self._fillcolor = other._fillcolor
+ self._effective_alphas = other._effective_alphas
def finalize(self):
"""
@@ -513,30 +513,33 @@ def _print_pgf_path_styles(self, gc, rgbFace):
# filling
has_fill = rgbFace is not None
- path_is_transparent = gc.get_alpha() != 1.0
- fill_is_transparent = has_fill and (len(rgbFace) > 3) and (rgbFace[3] != 1.0)
+
+ if gc.get_forced_alpha():
+ fillopacity = strokeopacity = gc.get_alpha()
+ else:
+ strokeopacity = gc.get_rgb()[3]
+ fillopacity = rgbFace[3] if has_fill and len(rgbFace) > 3 else 1.0
+
if has_fill:
writeln(self.fh, r"\definecolor{currentfill}{rgb}{%f,%f,%f}" % tuple(rgbFace[:3]))
writeln(self.fh, r"\pgfsetfillcolor{currentfill}")
- if has_fill and (path_is_transparent or fill_is_transparent):
- opacity = gc.get_alpha() * 1.0 if not fill_is_transparent else rgbFace[3]
- writeln(self.fh, r"\pgfsetfillopacity{%f}" % opacity)
+ if has_fill and fillopacity != 1.0:
+ writeln(self.fh, r"\pgfsetfillopacity{%f}" % fillopacity)
# linewidth and color
lw = gc.get_linewidth() * mpl_pt_to_in * latex_in_to_pt
stroke_rgba = gc.get_rgb()
writeln(self.fh, r"\pgfsetlinewidth{%fpt}" % lw)
writeln(self.fh, r"\definecolor{currentstroke}{rgb}{%f,%f,%f}" % stroke_rgba[:3])
writeln(self.fh, r"\pgfsetstrokecolor{currentstroke}")
- if gc.get_alpha() != 1.0:
- writeln(self.fh, r"\pgfsetstrokeopacity{%f}" % gc.get_alpha())
+ if strokeopacity != 1.0:
+ writeln(self.fh, r"\pgfsetstrokeopacity{%f}" % strokeopacity)
# line style
dash_offset, dash_list = gc.get_dashes()
- ls = gc.get_linestyle(None)
- if ls == "solid":
+ if dash_list is None:
writeln(self.fh, r"\pgfsetdash{}{0pt}")
- elif (ls == "dashed" or ls == "dashdot" or ls == "dotted"):
+ else:
dash_str = r"\pgfsetdash{"
for dash in dash_list:
dash_str += r"{%fpt}" % dash
@@ -289,7 +289,7 @@ def _write_default_style(self):
writer = self.writer
default_style = generate_css({
u'stroke-linejoin': u'round',
- u'stroke-linecap': u'square'})
+ u'stroke-linecap': u'butt'})
writer.start(u'defs')
writer.start(u'style', type=u'text/css')
writer.data(u'*{%s}\n' % default_style)
@@ -386,15 +386,21 @@ def _get_style_dict(self, gc, rgbFace):
"""
attrib = {}
+ forced_alpha = gc.get_forced_alpha()
+
if gc.get_hatch() is not None:
attrib[u'fill'] = u"url(#%s)" % self._get_hatch(gc, rgbFace)
+ if rgbFace is not None and len(rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha:
+ attrib[u'fill-opacity'] = str(rgbFace[3])
else:
if rgbFace is None:
attrib[u'fill'] = u'none'
elif tuple(rgbFace[:3]) != (0, 0, 0):
attrib[u'fill'] = rgb2hex(rgbFace)
+ if len(rgbFace) == 4 and rgbFace[3] != 1.0 and not forced_alpha:
+ attrib[u'fill-opacity'] = str(rgbFace[3])
- if gc.get_alpha() != 1.0:
+ if forced_alpha and gc.get_alpha() != 1.0:
attrib[u'opacity'] = str(gc.get_alpha())
offset, seq = gc.get_dashes()
@@ -404,12 +410,15 @@ def _get_style_dict(self, gc, rgbFace):
linewidth = gc.get_linewidth()
if linewidth:
- attrib[u'stroke'] = rgb2hex(gc.get_rgb())
+ rgb = gc.get_rgb()
+ attrib[u'stroke'] = rgb2hex(rgb)
+ if not forced_alpha and rgb[3] != 1.0:
+ attrib[u'stroke-opacity'] = str(rgb[3])
if linewidth != 1.0:
attrib[u'stroke-width'] = str(linewidth)
if gc.get_joinstyle() != 'round':
attrib[u'stroke-linejoin'] = gc.get_joinstyle()
- if gc.get_capstyle() != 'projecting':
+ if gc.get_capstyle() != 'butt':
attrib[u'stroke-linecap'] = _capstyle_d[gc.get_capstyle()]
return attrib
Oops, something went wrong.

0 comments on commit 6cc8aaa

Please sign in to comment.