Tuesday, August 29, 2017

Decorating the Oceans, Part Six (of Five)

I ended my last posting claiming that I was done with ocean decorations and moving on to labeling, but that turns out to be a lie.  I ran into some issues with illustrations, and resolving them makes some interesting use of SVG filters so I thought I'd write up what I did.

I ended the last posting with this image of an illustration on a map:
Per my comment in the last posting, I started experimenting with recreating these illustrations as SVG drawings for better flexibility.   While playing around with that, I discovered that illustrations didn't look nearly as good when there was a pattern on the ocean:
The pattern is underneath the illustration and shows through, making it very obvious that the illustration has just been "stamped" onto the top of the ocean.  In actuality, these sorts of illustrations usually appear on maps with heavily patterned oceans, and the artists took care to work them into the pattern:
Although, it should be noted, not always:
At this point I'm not interested in trying to actually work the illustration into the background.  But at least I can work on removing the background under the figure so it isn't so obviously dropped in to the map.

In general, the way to do this is to mask (or clip) out the background underneath the figure.  In this case, there are two difficulties with doing that.  First, the figure is actually being applied via an SVG filter, and it turns out that SVG masks do not work on SVG filters.  Second, to mask the figure out we need to create a mask of slightly larger size than the figure.  And since these illustrations are not nice geometric shapes, this is a problem.

There's a workaround that I can use to address the first problem.  It's used in this tutorial, although it isn't completely explained.  I can summarize the basic idea this way:  You use SVG filter capabilities to create an image representing the area you want to mask.  Then you combine this image with the filter using the SVG "feComposite" capability in a way that only keeps the parts of the filter that also have parts in the mask.  This is pretty esoteric SVG wizardry, so I won't go into great detail.  But if you want more info, email me and I'll give the full scoop.  Just trust me that I got it working :-).

Now that I have a working mask capability, I need to create the actual mask to use for wiping out the background behind the figure.  My first thought is to create a rectangular mask the size of the illustration.  (You can create a rectangular image in an SVG filter using "feFlood".)
This at least demonstrates the mask works, but it looks terrible.  One way to improve this would be to blur the edges:
That obscures the hard edge but is otherwise not much of an improvement.  I need a way to get the outline of the illustration.  Unfortunately, there doesn't seem to be any way to get the outline, or to fill the outline to create a mask. However, I do have the illustration itself, so maybe I can use that somehow.

Using the illustration itself as the mask won't work, because that will just block out the parts of the background that are already covered by the illustration.  But I could use the blur technique again to smear some of the illustrate outward (and inward):
I've reversed the masking here to make the effect more visible.  You can see some bits of the pattern showing through underneath the image, e.g., with the mask the right way around, these parts would be hidden.  The problem is that the effect is very slight.  What I really need is something like a filled-in version of the illustration.

As it happens, SVG filters have an effect called "feMorphology."  This effect makes lines heavier or thinner.  To demonstrate, I'll apply it to the actual illustration and thicken up the lines slightly:
That's not pretty, but demonstrates how I can use feMorphology to turn the illustration into something more useful as a filter.  If I increase the dilation a bit and add a blur I get this:
Which starts to look like something I could use as a mask.  Some tweaks give me this:
By adjusting the dilation and blur, I can make the cut-out tighter or sharper:
This approach doesn't work as well for an illustration that doesn't have as many lines or has large empty space in the middle:
This illustration is intentionally dim.  The masking works nicely around the heavy outline, but fails to cover the empty space in the middle of the fish.  By luck, in this case that happens to look okay.  The pattern that shows through looks like shading for the back of the fish.  But it doesn't usually look good:
This illustration is light enough that outside the dark sucker areas, the masking has hardly any effect.

To some extent, this problem can be addressed by careful selection of the illustrations, but if I want to be able to use a wide variety of illustrations with patterned backgrounds, I may need to create separate masking images for each illustration, and use those to accurately mask the illustration.

No comments:

Post a Comment