DropShadow Picture: Help wanted

Hi, I have a method that uses the ImagePlay library to draw a shadow behind a text. The shadow has several parameters (color, transparency, offset, blur, angle). In Project, there are two ways to draw the shadow that is created as a picture behind the text. Variant one, draws the shadow correctly with all parameters, but a white background color and variant two, which draws the shadow with its parameters only for certain colors, because the blur filter alienates the transparency value of the shadow color in the picture mask.

How can the white background color of the shadow image be removed for variant one so that the picture is drawn on the canvas without background (transparent)?

Xojo Forum Shadow

Are you targeting macOS only? If so, Apple have built a shadow function into the graphics layer, with some declares it’s not too difficult to utilize. However if you want x-plat then, you do need a 3rd Party library.

It sounds like the library you’re using is creating a mask, not the actual shadow. If you create a new blank picture of the same dimensions, fill it with black, then applyMask with the image from the library it should work (in theory).

Heck in the macOS, there’s even a way to get dropshadows and bevels from a NSLabel; but it got broken since Apple went flat, and I haven’t explored it much since then.

Thanks for reply Sam. I have a working code for macOS using declare & posted this some weeks ago. Currently I’m looking for a solution to use/emulate a Drop Shadow like the native macOS declare generated to work Windows & Linux. The post above was my idea.
So what do i need to change in the Blur Algorithm?

Does someone have a Xojo Translation for the Algorithms described at Fastest Gaussian Blur (in linear time) ?

OK, I tried to translate the source from the Link above, but there are two lines, I don’t know hoe to translate. I commented out them.

[h]Original (from link)[/h]

// source channel, target channel, width, height, radius function gaussBlur_1 (scl, tcl, w, h, r) { var rs = Math.ceil(r * 2.57); // significant radius for(var i=0; i<h; i++) for(var j=0; j<w; j++) { var val = 0, wsum = 0; for(var iy = i-rs; iy<i+rs+1; iy++) for(var ix = j-rs; ix<j+rs+1; ix++) { var x = Math.min(w-1, Math.max(0, ix)); var y = Math.min(h-1, Math.max(0, iy)); var dsq = (ix-j)*(ix-j)+(iy-i)*(iy-i); var wght = Math.exp( -dsq / (2*r*r) ) / (Math.PI*2*r*r); val += scl[y*w+x] * wght; wsum += wght; } tcl[i*w+j] = Math.round(val/wsum); } }

[h]My attempt to translate the algorithm[/h]

[code]Private Function GaussianBlur(source As Picture, width As Integer, height As Integer, radius As Double) As Picture
Const PI = 3.14159265359

Dim surf As RGBSurface = source.RGBSurface
Dim result As Picture = New Picture(source.Width, source.Height)
Dim rs As Double = Ceil(radius * 2.57) ’ significant radius

For i As Integer = 0 To height -1

For j As Integer = 0 To width - 1

Dim val, wsum As Integer
Dim iy As Double
Dim a As Double = i + radius + 1

For iy = i - radius To  a
  
  Dim ix As Double
  Dim b As Double = j + radius +1
  
  For ix = j - radius To b
    
    Dim x As Double = Min(width - 1, Max(0, ix))
    Dim y As Double = Min(height - 1, Max(0, iy))
    Dim dsq As Double = (ix - j) * (ix - j) + (iy - i) * (iy - i)
    Dim wght As Double = Exp( -dsq / (2 * radius * radius) ) / (PI * 2 * radius * radius)
    
    ' val = val + source(y*w+x) * wght ' What to do here? RGBSurface.Pixel?
    wsum = wsum + wght
    
  Next
  
  ' result[i*w+j] = Round(val / wsum) ' What to do here? RGBSurface.Pixel?
  
Next

Next

Next

Return result
End Function[/code]

I’m still not clear what you want to achieve. The ImagePlayLibrary has working blurs. Try to find a Java or JavaScript variation of the algorithm above. Those languages are less obtuse than C. For instance see https://stackoverflow.com/questions/21418892/understanding-super-fast-blur-algorithm . That looks quite comparable to Xojo.

A quick glance at the C code: you have 2 loops with width and height. C treats everything as array. So tcl[i*w+j] would be a pixel in your RGBSurface.

If you’re getting an image from that library which has a white background, but the correct shadow in grey, I would suggest you invert that and use that as a mask.

That’s a ■■■■■■■ horrific example of a Gaussian blur! At least in my opinion. Gaussian Blur isn’t as complicated as you think.

I have two suggestions;

  1. look at https://www.einhugur.com/ for pictureEffects plugin.
  2. If you want to do a Gaussian Blur yourself, even as an exercise. I’ll provide you with some links on optimized Gaussian blurs, it’s some good reading.

p.s. I don’t actually have a Gaussian Blur written in native Xojo, otherwise I’d share it with you. I have other averaging filters, but they’re written in GLSL.

This is a very good and simple suggestion. This only raises the question of how I can give the shadow colors or color the shadow again after I have added it as a mask.

There are reasons why I can’t fall back on plugins at this point and need a solution in pure Xojo.

When you create the image that you’re going to mask, you first fill it with the color that you desire as the shadow color.

Performance wise and ease of implementing, I would recommend a plugin for this. If you want to write a fast Gaussian Blur in Xojo, it will take some time.

Below is a rough translation of a Box blur written in GLSL, it uses the double pass technique. The first reduction filter I wrote in GLSL was a boxBlur, so I figured it might be a good starting point for you. A Gaussian Blur, is basically the same, except that it weighs the values based upon their closeness to the global co-ordinates.

There’s a whole host of things you can do to optimize this code further. It takes 0.6 seconds to process a 300 x 300 picture with a radius of 3, tested on a 2015 12" Retina MacBook 1.1 Ghz. I doubt you’ll match the performance of GLSL, which can do this in less than 0.002 of a second.

[code]Public Function splitBoxBlur(sourceImage as picture, radius as integer) as picture
// — This is a rough translation from a BoxBlur filter written in GLSL by Sam Rowlands.
#pragma backgroundTasks false
#pragma stackOverflowChecking false
#pragma nilObjectChecking false

Dim rvalue as new picture( sourceImage.width, sourceImage.height )
Dim inSurface as RGBSurface = sourceImage.rGBSurface
Dim outSurface as RGBSurface = rvalue.RGBSurface

Dim maxX as integer = sourceImage.width - 1
Dim maxY as integer = sourceImage.height - 1
Dim lYMin, lyMax, lxMin, lxMax as integer
Dim red, green, blue, count as Uint64
Dim c as color

For globalY as integer = 0 to maxY
For globalX as integer = 0 to maxX
red = 0
green = 0
blue = 0
count = 0

  lxMin = if( globalX - radius < 0, 0, globalX - radius )
  lxMax = if( globalX + radius > maxX, maxX, globalX + radius )
  
  For x as integer = lxMin to lxMax
    c = inSurface.pixel( x, globalY )
    red = red + c.red
    green = green + c.green
    blue = blue + c.blue
    count = count + 1
  Next
  
  outSurface.pixel( globalX, globalY ) = rgb( red / count, green / count, blue / count )
Next

Next

For globalY as integer = 0 to maxY
For globalX as integer = 0 to maxX
red = 0
green = 0
blue = 0
count = 0

  lyMin = if( globalY - radius < 0, 0, globalY - radius )
  lyMax = if( globalY + radius > maxY, maxY, globalY + radius )
  
  For y as integer = lyMin to lyMax
    c = outSurface.pixel( globalx, y )
    red = red + c.red
    green = green + c.green
    blue = blue + c.blue
    count = count + 1
  Next
  
  outSurface.pixel( globalX, globalY ) = rgb( red / count, green / count, blue / count )
Next

Next

return rvalue
End Function
[/code]

What is GLSL?

Thanks for your suggestion Sam. Sadly this Blur Method also results the transparent background of the source image into black.

https://www.khronos.org/registry/OpenGL/index_gl.php/

If you want a different behaviour then change the algorithm. Process the mask separately from the picture itself.

OpenGL Shader Language; it’s code that runs on the GPU and is incredibly fast, even without maximum optimization. While the language it’self is x-plat, I only know how to execute it on macOS, I need to take some time and figure out how to utilize it on Windows and Linux.

With some modification, it could be made to work on the alpha channel as well. Xojo color has an alpha property, it shouldn’t be too hard to figure out how to process it (like the other channels) :slight_smile:

This was the first step I did, to add the Alpha calculations to your method. I’ve updated the Project, so you can see what I’ve done. The background color is still black, after blurring. Looks like I missed something.

Xojo Forum Shadow.xojo_binary_project