Gradient Text

I was wondering if there was a way to get some gradient filled text, with a linear blend from top to bottom.

I did a lot of searching and playing around and I came to the conclusion that there wasn’t any way of doing this straightforwardly with a linear gradient brush or as a special draw text method or anything.

So I started of thinking of ways of achieving the same effect but the only Idea I could come up with was using a memory dc, drawing the text in white over say a black background, setting the bitmap mask colour to white, placing that over some linear gradient and then setting the mask colour to black so just the gradient in the text remained but of course because of the anti aliasing any colour values between the white and black remain around the letters as noise.

I then thought about looping over the pixels and setting their alpha values based on they greyscale colour but that would surely be very inefficient.

Other than that I can’t think of a way to achieve this effect.

Has anyone tried this before? or does anyone have any ideas?

Paul wrote:

I was wondering if there was a way to get some gradient filled text,
with a linear blend from top to bottom.

I did a lot of searching and playing around and I came to the
conclusion that there wasn't any way of doing this straightforwardly
with a linear gradient brush or as a special draw text method or anything.

Well, I can tell you how to do that in the Windows API, but I don't know
how this maps to wx.

In Windows, you use BeginPath, then TextOut, then EndPath. That creates
a "path" out of the glyphs in your text drawing. Now, you can convert
that path to a region, set that region as your clipping region, and do a
simple rectangular gradient fill through that clipping region. The
gradient will only show through where the clipping region allows it to.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Hm interesting I’ll see if I can find a way to do this in wx. Do you know if clipping regions can have alpha edges for the anti aliasing of the text?

···

On 16 May 2012 18:25, Tim Roberts timr@probo.com wrote:

Paul wrote:

I was wondering if there was a way to get some gradient filled text,

with a linear blend from top to bottom.

I did a lot of searching and playing around and I came to the

conclusion that there wasn’t any way of doing this straightforwardly

with a linear gradient brush or as a special draw text method or anything.

Well, I can tell you how to do that in the Windows API, but I don’t know

how this maps to wx.

In Windows, you use BeginPath, then TextOut, then EndPath. That creates

a “path” out of the glyphs in your text drawing. Now, you can convert

that path to a region, set that region as your clipping region, and do a

simple rectangular gradient fill through that clipping region. The

gradient will only show through where the clipping region allows it to.

Tim Roberts, timr@probo.com

Providenza & Boekelheide, Inc.

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

Paul Wiseman wrote:

Hm interesting I'll see if I can find a way to do this in wx. Do you
know if clipping regions can have alpha edges for the anti aliasing of
the text?

No, I think you're going to find they are hard-edged. It's not clear
that anti-aliasing is really going to serve any purpose with
gradient-colored text -- you're already giving up on maximizing readability.

···

--
Tim Roberts, timr@probo.com
Providenza & Boekelheide, Inc.

Yea, it would only be a slight gradient on some large text though, 30 or so point size. Its the client who wants it, I think it’s a bad idea too :slight_smile:

···

On 16 May 2012 21:20, Tim Roberts timr@probo.com wrote:

Paul Wiseman wrote:

Hm interesting I’ll see if I can find a way to do this in wx. Do you

know if clipping regions can have alpha edges for the anti aliasing of

the text?

No, I think you’re going to find they are hard-edged. It’s not clear

that anti-aliasing is really going to serve any purpose with

gradient-colored text – you’re already giving up on maximizing readability.

Tim Roberts, timr@probo.com

Providenza & Boekelheide, Inc.

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

I got it in the end although you have to pass a background colour to the function. I’ve also written one which loops over all the pixels setting alpha values as well if I ever want to draw the text on a background that isn’t a solid colour but probably not as it is roughly 40-50 times slower

I’ll paste them here just in case anyone else might find them useful

def get_gradient_text_solid_bg(text,font,point_size,top_colour,bottom_colour,bg_colour_tuple):

dc=wx.MemoryDC()

f=wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)

f.SetFaceName(font)

f.SetPointSize(point_size)

dc.SetFont(f)

dc.SelectObject(wx.EmptyBitmap(0,0)) #Cant GetTextExtent without a bitmap selected

w,h= dc.GetTextExtent(text)

template_bmp= wx.EmptyBitmap(w,h)

dc.SelectObject(template_bmp)

dc.SetBackground(wx.Brush(wx.WHITE))

dc.Clear()

dc.DrawText(text,0,0)

dc.SelectObject(wx.NullBitmap)

template_image= template_bmp.ConvertToImage()

template_image.ConvertColourToAlpha(*bg_colour_tuple)

template_bmp= template_image.ConvertToBitmap()

text_bmp= wx.EmptyBitmap(w,h)

dc.SelectObject(text_bmp)

dc.GradientFillLinear((0,0,w,h),top_colour,bottom_colour,wx.SOUTH)

dc.DrawBitmap(template_bmp,0,0)

dc.SelectObject(wx.NullBitmap)

return text_bmp

def get_gradient_text(text,font,point_size,top_colour,bottom_colour):

dc=wx.MemoryDC()

f=wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)

f.SetFaceName(font)

f.SetPointSize(point_size)

dc.SetFont(f)

bitmap_1x1= wx.EmptyBitmap(1,1)

dc.SelectObject(bitmap_1x1)

w,h= dc.GetTextExtent(text)

template_bmp= wx.EmptyBitmap(w,h)

dc.SelectObject(template_bmp)

dc.SetBackground(wx.Brush(wx.BLACK))

dc.Clear()

dc.SetTextForeground(wx.WHITE)

dc.DrawText(text,0,0)

dc.SelectObject(wx.NullBitmap)

text_bmp= wx.EmptyBitmap(w,h)

dc.SelectObject(text_bmp)

rect= wx.Rect(0,0,w,h)

dc.GradientFillLinear(rect,top_colour,bottom_colour,wx.SOUTH)

dc.SelectObject(wx.NullBitmap)

template_image= template_bmp.ConvertToImage()

text_image= text_bmp.ConvertToImage()

for x in xrange(w):

for y in xrange(h):

text_image.SetAlpha(x,y,template_image.GetRed(x,y))

text_bmp= text_image.ConvertToBitmap()

return text_bmp

···

On 17 May 2012 00:20, Paul Wiseman poalman@gmail.com wrote:

On 16 May 2012 21:20, Tim Roberts timr@probo.com wrote:

Paul Wiseman wrote:

Hm interesting I’ll see if I can find a way to do this in wx. Do you

know if clipping regions can have alpha edges for the anti aliasing of

the text?

No, I think you’re going to find they are hard-edged. It’s not clear

that anti-aliasing is really going to serve any purpose with

gradient-colored text – you’re already giving up on maximizing readability.

Tim Roberts, timr@probo.com

Providenza & Boekelheide, Inc.

To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com

or visit http://groups.google.com/group/wxPython-users?hl=en

Yea, it would only be a slight gradient on some large text though, 30 or so point size. Its the client who wants it, I think it’s a bad idea too :slight_smile:

I got it in the end although you have to pass a background colour to the
function. I've also written one which loops over all the pixels setting
alpha values as well if I ever want to draw the text on a background that
isn't a solid colour but probably not as it is roughly 40-50 times slower

I'll bet you could make that MUICH faster with numpy. See Google or
the Wiki for examples of how to go between exImage and numpy arrays.

-Chris

···

On Thu, May 17, 2012 at 9:59 AM, Paul Wiseman <poalman@gmail.com> wrote:

I'll paste them here just in case anyone else might find them useful

def
get_gradient_text_solid_bg(text,font,point_size,top_colour,bottom_colour,bg_colour_tuple):
dc=wx.MemoryDC()
f=wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
f.SetFaceName(font)
f.SetPointSize(point_size)
dc.SetFont(f)
dc.SelectObject(wx.EmptyBitmap(0,0)) #Cant GetTextExtent without a
bitmap selected
w,h= dc.GetTextExtent(text)
template_bmp= wx.EmptyBitmap(w,h)
dc.SelectObject(template_bmp)
dc.SetBackground(wx.Brush(wx.WHITE))
dc.Clear()
dc.DrawText(text,0,0)
dc.SelectObject(wx.NullBitmap)
template_image= template_bmp.ConvertToImage()
template_image.ConvertColourToAlpha(*bg_colour_tuple)
template_bmp= template_image.ConvertToBitmap()
text_bmp= wx.EmptyBitmap(w,h)
dc.SelectObject(text_bmp)
dc.GradientFillLinear((0,0,w,h),top_colour,bottom_colour,wx.SOUTH)
dc.DrawBitmap(template_bmp,0,0)
dc.SelectObject(wx.NullBitmap)
return text_bmp

def get_gradient_text(text,font,point_size,top_colour,bottom_colour):
dc=wx.MemoryDC()
f=wx.SystemSettings_GetFont(wx.SYS_DEFAULT_GUI_FONT)
f.SetFaceName(font)
f.SetPointSize(point_size)
dc.SetFont(f)
bitmap_1x1= wx.EmptyBitmap(1,1)
dc.SelectObject(bitmap_1x1)
w,h= dc.GetTextExtent(text)
template_bmp= wx.EmptyBitmap(w,h)
dc.SelectObject(template_bmp)
dc.SetBackground(wx.Brush(wx.BLACK))
dc.Clear()
dc.SetTextForeground(wx.WHITE)
dc.DrawText(text,0,0)
dc.SelectObject(wx.NullBitmap)
text_bmp= wx.EmptyBitmap(w,h)
dc.SelectObject(text_bmp)
rect= wx.Rect(0,0,w,h)
dc.GradientFillLinear(rect,top_colour,bottom_colour,wx.SOUTH)
dc.SelectObject(wx.NullBitmap)
template_image= template_bmp.ConvertToImage()
text_image= text_bmp.ConvertToImage()
for x in xrange(w):
for y in xrange(h):
text_image.SetAlpha(x,y,template_image.GetRed(x,y))
text_bmp= text_image.ConvertToBitmap()
return text_bmp

--
To unsubscribe, send email to wxPython-users+unsubscribe@googlegroups.com
or visit http://groups.google.com/group/wxPython-users?hl=en

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov

For the looping over pixels? I think you’re right, that’s a good idea! I can’t afford to bundle all of numpy in with my app so I’ll see if it’s possible to just pull in the bits I need into py2app/py2exe

···

On 17 May 2012 21:03, Chris Barker chris.barker@noaa.gov wrote:

On Thu, May 17, 2012 at 9:59 AM, Paul Wiseman poalman@gmail.com wrote:

I got it in the end although you have to pass a background colour to the

function. I’ve also written one which loops over all the pixels setting

alpha values as well if I ever want to draw the text on a background that

isn’t a solid colour but probably not as it is roughly 40-50 times slower

I’ll bet you could make that MUICH faster with numpy. See Google or

the Wiki for examples of how to go between exImage and numpy arrays.

-Chris

For the looping over pixels?

exactly

I'll see if it's

possible to just pull in the bits I need into py2app/py2exe

that's a bit of pain, actually, numpy imports a bunch of extra stuff
-- so it's a bit hard to only include what you really use -- though
once you've got wxPython in there, it's not that big...

-Chris

···

On Thu, May 17, 2012 at 2:05 PM, Paul Wiseman <poalman@gmail.com> wrote:

--

Christopher Barker, Ph.D.
Oceanographer

Emergency Response Division
NOAA/NOS/OR&R (206) 526-6959 voice
7600 Sand Point Way NE (206) 526-6329 fax
Seattle, WA 98115 (206) 526-6317 main reception

Chris.Barker@noaa.gov