Re: [filter-effects] resolution dependent filter primitives

On Nov 5, 2013, at 1:01 AM, Michael Mullany <michael@sencha.com<mailto:michael@sencha.com>> wrote:


On Mon, Aug 26, 2013 at 9:28 PM, Dirk Schulze <dschulze@adobe.com<mailto:dschulze@adobe.com>> wrote:
Hi,

This is a follow up on Stephen White's mail "Filter Effects and High DPI"[2]

The Filter Effects spec[1] has a couple of filter primitives that are resolution dependent. Namely: feConvolutionMatrix, feDiffuseLighting, feSpecularLighting and feCustom.

With removing 'filterRes', there is just 'kernelUnitLength' that can be used to "hard code" a resolution for a primitive. 'filterRes' defined the resolution for the whole filter chain which reduced or increased pixel density for each filter primitive instead of one. This either caused unnecessary oversampling of filter operations but more often: unnecessary reduction of quality. With 'kernelUnitLength' the affect of over- or undersampling can be localized to exactly one primitive where the primitive values can not be scaled for resolution independent results.

If 'kernelUnitLength' is not set, all the primitives in the introduction may depend on the device pixel ratio and are therefore platform dependent. This is actually hardly a "retina" vs "normal" screen problem. SVG is scalable by nature and therefore you can see the problem on any screen today. Open the following example in a browsers and resize the window:

        http://www.w3.org/Graphics/SVG/Test/20110816/svg/filters-conv-01-f.svg

You'll see that you don't have consistent results. If you make the window smaller, the top left image gets more blurry and the top right image more sharpen. Same happens if you zoom into a page where one of the above primitives was applied.

We could create stable results by default. UAs could set 'kernelUnitLength' such that the kernel size is always relative to a CSS pixel in the current local coordinate system of the filtered object. This is something that is nearly impossible to determine for the author if he wants to use the same filter on different objects. With the auto calculated 'kernelUnitLength' the proportion of the filter chain result looks always the same across platforms but might be more pixelated on one platform and less pixelated on another one.

It is unclear what is better for the users:
* best results that are highly platform dependent and indeed differ significantly, or
* platform independent results that might be pixelated.

During my research I couldn't find one SVG example where the above primitives are used in combination of either 'filterRes' or 'kernelUnitLength'. Not even in the SVG test suite. That means these examples in the web out there are all suffering from device and zoom dependent filter results.

I would even suggest removing 'kernelUnitLength' as well and choose one of the above two ways (high DPI but resolution dependent results, or pixelated proportion stable results). Or let the author choose between one of the two options and have one as fallback.

Does anyone have a comment?


I got around to doing a thorough testing of feDiffuseLighting + fePointLight cross browser and generated a test page for people to play with.

The page is here: http://codepen.io/mullany/pen/wKJeu (note this takes a while to render in IE10 due to lack of support for objectBoundingBox units for kernelUnitLength)

It's not very surprising that there is not much content using these settings because they don't work consistently cross browser. Here's what I found:

 *   kernelUnitLength: supported by IE10, Firefox (no support in Safari or Chrome)
 *   filterRes: supported by Chrome, Safari, Firefox (no support in IE10)
 *   primitiveUnits = userSpaceOnUse -> supported everywhere
 *   primitiveUnits = objectBoundingBox -> supported by Firefox,  (no support in Safari, Chrome, IE10: units are interpreted as userSpace units)
    *   This makes kernelUnitLengths specified in OBB units cause very very long render times in browsers (aka IE10) that support kernelUnitLength, but don't support objectBoundingBox units - because it thinks I'm asking for a very small kernelUnitLength

This test page raised one or two notes for the current spec:

 *   The spec is not clear what Z position units are calculated relative to, when primitiveUnits = objectBoundingBox -> X? Y? Some average thereof?
 *   The spec is not clear that surfaceScale units are in pixels, not in primitiveUnits (or if they're supposed to be primitiveUnits, it should say that - no browser currently supports this)

In any case, the use case I'm running into is not a high dpi vs. low dpi problem (because OBB units should be able to solve this, I think?) Instead, it's the fact that Firefox (specifically) chooses a fast, low quality default for lighting effects which are too coarse to use in image filters. The mozilla implementor has told me to use a higher filterRes, but since all positions are scaled by the ratio of filterRes to default filterRes (aka when you double the filterRes, the X, Y and Z positions of your image source are also scaled up by 2x), you end up with what is effectively a new unit system just for lightsource positions that has nothing to do with any other unit system (unless you also reduce the kernelUnitLength to compensate).  [As an aside, the practical effect of this in Firefox was no increase in quality (and I've filed a bug against that)].

It would all be a lot simpler if there was an attribute similar to shape-rendering (filter-rendering?) that would allow optimizeSpeed vs. optimizeQuality for these primitives.

I need to verify your test case. All arguments are supposed to be pixels and therefore are just integer and floats (floats for oversampling) and don’t have px, cm or any other length value.

I agree that Firefox implemented some values like stdDeviation from feGaussianBlur relative to the value of primitiveUnits. A reason why WebKit did it as well. Not sure if that was the initial intension of the spec though. I rather think that primitiveUnits should just be taken into account for x,y,width and height of the subregions, but kernelUnitLength is indeed one use case where it makes sense to have it relative to primitiveUnits. I’ll add an issue to the spec.

That said, your conclusion that WebKit and Blink do not support primtitiveUnits in general is not correct. in the cases described above, both engines should take primitiveUnits into account.

I compare Z to the value of z on transform-origin or perspective-origin from CSS Transforms. You can not have percentage values there because you don’t know how they would be relative to the x and y dimension. Therefore, Z should always operate in userSpaceOnUse. I'll add an issue to the spec.

filterRes was deprecated and removed from the spec. It is just kernelUnitLength that is left.

I am not convinced if it is worth it to keep kernelUnitLength. You never know how kernelUnitLength is relative to device units OR to your object, see previous discussions. So you are better on with having high DPI results but platform dependent or you want to have it exactly depending on your userSpaceInUse coordinates which probably will reduce quality. Of course, if you put it in userSpaceOnUse, there are cases where you could ridiculously increase the pixel density and the browser may need to reduce it again or runs out of memory. Example:

<g transform=“scale(0.0001)”>
<g filter=“url(#filter)”>
<rect transform=“scale(100)” width=“1000” height=“1000"/>
</g>
</g>

The resulting rect size would be 100x100, yet the filtered object would be 100000x100000.

So even if we add a flag to switch between device pixels and userSpaceOnUse, it would still just be a hint for the UA.

Greetings,
Dirk










Greetings,
Dirk


[1] http://dev.w3.org/fxtf/filters/
[2] http://lists.w3.org/Archives/Public/public-fx/2013JanMar/0149.html



--
www.sencha.com<http://www.sencha.com/>
"Amazing Apps with Web Technologies"

Received on Tuesday, 5 November 2013 06:31:38 UTC