Canvas - Text w/Outlining

Is there a way to paint text on the canvas that is outlined? i.e. painting text over a background image that could have very similar colors, thus I wish to outline the text for clarity.

here is an idea…

g.forecolor=&cc0c0c0 ' gray - or outline color
g.drawstring s,x-1,y-1
g.drawstring s,x+1,y+1
g.drawstring s,x-1,y+1
g.drawstring s,x+1,y-1
g.forecolor=&cff0000 ' red - or text color you want
g.drawstring s,x,y

off the top of my head… I have NO idea how clean it will look

Try drawing the text offset slightly in a different color first, the the actual text on top of it (drop shadow). Or slightly offset up/left in a larger size for full outline.

Thanks Guys… Painting in the outline color (black) 1 px to the top and left, 1 px to the bottom and right then in the foreground color (white) right on x, y worked beautifully. For some reason I didn’t think that would work out, but it did! I used the same font size for all three drawstring calls.

Didn’t think about doing it in three calls, but that removes the need for figuring out the right size to use. Nice!

Under Cocoa you can enable DropShadows. (looks really nice!)

To add a DropShadow to graphics in Cocoa:

Sub CGSetShadow(g As Graphics, xOffset As integer, yOffset As integer, blur As Double, c as Color)
#if TargetCocoa then
declare sub CGContextSetShadowWithColor lib “Cocoa” (context as integer,offset as cgsize,blur as single,c as ptr)
declare function CGColorSpaceCreateDeviceRGB lib “Cocoa” () as ptr
declare function CGColorCreate lib “Cocoa” (colorspace as ptr, val as ptr) as ptr
declare sub CGColorRelease lib “Cocoa” (c as ptr)
declare sub CGColorSpaceRelease lib “Cocoa” (c as ptr)
dim offset As CGSize
offset.width=xOffset
offset.height=0-yOffset
dim cgcm As MemoryBlock
dim cgcolor As ptr
cgcm= new MemoryBlock(16)
cgcm.SingleValue(0)=c.red/255
cgcm.SingleValue(4)=c.Green/255
cgcm.SingleValue(8)=c.Blue/255
cgcm.SingleValue(12)=(255-c.Alpha)/255
dim cgcspace as ptr=CGColorSpaceCreateDeviceRGB
cgcolor=CGColorCreate(cgcspace,cgcm)
CGColorSpaceRelease(cgcspace)
CGContextSetShadowWithColor g.Handle(Graphics.HandleTypeCGContextRef),offset,blur,cgcolor
if cgcolor<>nil then CGColorRelease(cgcolor)

#endif
End Sub

And to turn them back off:

Sub CGClearShadow(g As Graphics)
#if TargetCocoa then
declare sub CGContextSetShadowWithColor lib “Cocoa” (context as integer,offset as CGSize,blur as single,c as ptr)
dim s As CGSize
CGContextSetShadowWithColor g.Handle(Graphics.HandleTypeCGContextRef),s,0,nil
#endif
End Sub

Don’t forget to add the CGSize struct!
width as single
height as single

Enjoy!

[quote=53488:@jim mckay]Under Cocoa you can enable DropShadows. (looks really nice!)

To add a DropShadow to graphics in Cocoa:

Sub CGSetShadow(g As Graphics, xOffset As integer, yOffset As integer, blur As Double, c as Color)
#if TargetCocoa then
declare sub CGContextSetShadowWithColor lib “Cocoa” (context as integer,offset as cgsize,blur as single,c as ptr)
declare function CGColorSpaceCreateDeviceRGB lib “Cocoa” () as ptr
declare function CGColorCreate lib “Cocoa” (colorspace as ptr, val as ptr) as ptr
declare sub CGColorRelease lib “Cocoa” (c as ptr)
declare sub CGColorSpaceRelease lib “Cocoa” (c as ptr)
dim offset As CGSize
offset.width=xOffset
offset.height=0-yOffset
dim cgcm As MemoryBlock
dim cgcolor As ptr
cgcm= new MemoryBlock(16)
cgcm.SingleValue(0)=c.red/255
cgcm.SingleValue(4)=c.Green/255
cgcm.SingleValue(8)=c.Blue/255
cgcm.SingleValue(12)=(255-c.Alpha)/255
dim cgcspace as ptr=CGColorSpaceCreateDeviceRGB
cgcolor=CGColorCreate(cgcspace,cgcm)
CGColorSpaceRelease(cgcspace)
CGContextSetShadowWithColor g.Handle(Graphics.HandleTypeCGContextRef),offset,blur,cgcolor
if cgcolor<>nil then CGColorRelease(cgcolor)

#endif
End Sub

And to turn them back off:

Sub CGClearShadow(g As Graphics)
#if TargetCocoa then
declare sub CGContextSetShadowWithColor lib “Cocoa” (context as integer,offset as CGSize,blur as single,c as ptr)
dim s As CGSize
CGContextSetShadowWithColor g.Handle(Graphics.HandleTypeCGContextRef),s,0,nil
#endif
End Sub

Don’t forget to add the CGSize struct!
width as single
height as single

Enjoy![/quote]

Reviving this thread for sure :slight_smile:

Jim I have a canvas that sits atop of a container. I want to use NSShadow on the edges of the canvas. I am having problems getting any combination of your above code to give me a preview.app like shadow on this canvas. Do you have any suggestions for me since this is new to me?

Thank you in advance!
Mike

My issue is with the offsets trying to get shadow coverage all around the canvas. :slight_smile: Making progress though:)

If you’re trying to get the effect of the container having a shadow, just enable the shadow in the paint event of the window and fill the shape of the container… ie (with the code above)

Sub Paint(g As Graphics, areas() As REALbasic.Rect) CGSetShadow(g,0,10,10.0,&c000000aa) g.FillRect(ContainerControl11.Left,ContainerControl11.top,ContainerControl11.Width,ContainerControl11.Height) End Sub

will give the container a floating appearance.

awesome thanks Jim!!!

After almost two years of silence I am trying to revive this threat once again.

I like the trick @Dave S gave us, right in the beginning of this threat. But when the size of the stroke is large (for whatever reason), isn’t it nicer to have a Declare take care of that? Dave’s suggestion is cross platform.

I found something on the Apple’s Developers site. It has something to do with setting a property called “cgtextdrawingmode”. There is a constant called “kCGTextFillStroke”.

Now, I have no idea how to deal with Declares. (I really should start to get into that, someday)
Is there some xojo user out there who has experience with Declares and willing to help the community out? :slight_smile:

[code]Sub Paint(g As Graphics, areas() As REALbasic.Rect) Handles Paint

//enable text stroking
dim gg As Ptr = Ptr( g.Handle(Graphics.HandleTypeCGContextRef) )

declare sub CGContextSetTextDrawingMode lib “CoreGraphics” (cntxt As Ptr, mode As UInteger)

CGContextSetTextDrawingMode(gg, 1) //1 = kCGTextStroke

//draw with Xojo
g.ForeColor = &cFF0000
g.TextSize = 40
g.DrawString “fubar”, 100, 100

//disable stroking
CGContextSetTextDrawingMode(gg, 0) //0 = kCGTextFill

End Sub
[/code]

This will outline the text drawn with Xojos built-in text drawing method. However it uses a default line width and to change that I think requires building a NSAttributedString (where width is set) and CTLine and other complicated stuff. I have code for making these objects but it’s not as robust as Xojos text drawing (only 1 line of text) and it’s not 64bit ready. Maybe look in MacOSLib and/or iOSLib.

That really looks promising. And it actually works. And it is a good start. The only challenge is the “NSAttributedString”. And in case Windows users need to find another Declare. But I love it. Thanks Will

Actually it doesn’t
What this function does is drawing ONLY the outline, with the pensize you define in the graphics object, and with the color defined in the ForeColor property.

So, if you want a White text with a 2 pixel Blue outline you can do the following:


Function TextStroke(extends g as Graphics, assigns Value as boolean)
    // have this function sit in a global module, in order to have access to it elsewhere in your code
    #if TargetMacOS
      dim gg As Ptr = Ptr( g.Handle(Graphics.HandleTypeCGContextRef) )
      declare sub CGContextSetTextDrawingMode lib "CoreGraphics" (cntxt As Ptr, mode As UInteger)
      dim mode as UInteger = if(Value, 1, 0)
      CGContextSetTextDrawingMode(gg, mode) 
    #endif
End Function


//draw the regular text with Xojo
  g.ForeColor = &cFFFFFF
  g.TextSize = 40
  g.DrawString "foobar", 100, 100

//draw the outline text in a second pass
  g.ForeColor = &c0000FF   ' stroke color
  g.PenWidth = 2  ' stroke thickness
  g.PenHeight = 2
  g.TextStroke = true  ' enable stroke function
  g.DrawString "foobar", 100, 100
  g.TextStroke = false  ' disabling the stroke, just in case

Actually, if you’re working in a recent version of Xojo, you might try the drawing technique whilst changing Graphics.ScaleX and ScaleY. That may allow you to control the stroke width better.

I don’t really understand your point. How can the scale give me more control over the stroke?

Is there an Direct2D ambivalent (declare) to get such a native Solution also on Windows and Linux? Has anyone experiences? I‘m working with Xojo 2018.2.