Re: [filter-effects] resolution dependent filter primitives

On Mon, Nov 4, 2013 at 10:30 PM, Dirk Schulze <dschulze@adobe.com> wrote:

>
> On Nov 5, 2013, at 1:01 AM, Michael Mullany <michael@sencha.com> wrote:
>
>
> On Mon, Aug 26, 2013 at 9:28 PM, Dirk Schulze <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.
>

Just to clarify, the following lighting related units are defined in
primitiveUnits, not pixels in both the SVG 1.1 spec and the current filter
effects 1.0 draft

   - kernelUnitLength in feDiffuseLighting & feSpecularLighting
   -  X, Y,Z in fePointlight
   -  X, Y, Z, PointsAtX, PointsAtY, PointsAtZ, in feSpotlight


> 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.
>

In both SVG 1.1, and in the current filter effects 1.0 draft - stdDeviation
for GaussianBlur as well as kernelUnitLength for feDiffuseLighting and
feSpecularLighting are all defined as primitiveUnits. From the specs:

 stdDeviation = "*<number-optional-number>
<http://www.w3.org/TR/SVG/types.html#DataTypeNumberOptionalNumber>*"
The standard deviation for the blur operation. If two
<number><http://www.w3.org/TR/SVG/types.html#DataTypeNumber>s
are provided, the first number represents a standard deviation value along
the x-axis of the coordinate system established by attribute
‘primitiveUnits’<http://www.w3.org/TR/SVG/filters.html#FilterElementPrimitiveUnitsAttribute>
on
the ‘filter’ <http://www.w3.org/TR/SVG/filters.html#FilterElement> element.
‘kernelUnitLength’<http://www.w3.org/TR/SVG/filters.html#feDiffuseLightingKernelUnitLengthAttribute>,
in combination with the other attributes, defines an implicit pixel grid in
the filter effects coordinate system (i.e., the coordinate system
established by the
‘primitiveUnits’<http://www.w3.org/TR/SVG/filters.html#FilterElementPrimitiveUnitsAttribute>
 attribute)


>
> 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 should have been clearer - I was talking solely about the context of the
test page - meaning that they don't currently support
primitiveUnits=objectBoundingBox specifically for fePointlight X,Y,Z
positions. No generalization was intended (although I also know that
feSpotlight positions also do not currently support objectBoundingBox units
in Chrome or Webkit)


>
> 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.
>

I think I inappropriately slandered the draft spec wrt its definition of Z
-> The spec currently states:

   "Z location for the light source in the coordinate system established by
attribute ‘primitiveUnits’<http://www.w3.org/TR/filter-effects/#FilterElementPrimitiveUnitsAttribute>
on
the <filter> <http://www.w3.org/TR/filter-effects/#FilterElement> element,
assuming that, in the initial coordinate
system<http://www.w3.org/TR/2011/REC-SVG11-20110816/coords.html#InitialCoordinateSystem>
,
the positive Z-axis comes out towards the person viewing the content and
assuming that one unit along the Z-axis equals one unit in X and
Y<http://www.w3.org/TR/SVG11/coords.html#Units_viewport_percentage>
"

one unit in X and Y is in turn defined as " sqrt((*actual-width*)**2 + (
*actual-height*)**2))/sqrt(2)."

I can see many use cases where you want X, Y and Z of a pointlight source
defined in objectBoundingBox units, so you can apply the same filter to a
bunch of differently sized content for example for consistent embossing,
without having to recalculate Z units . So the current spec language seems
fine to me.


>
> 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.
>

Given that it's already implemented in both Firefox and IE10+, I'd vote for
retaining kernelUnitLength as the way to poke the UA to do the "right
thing" however the developer/author chooses to define that, rather than
introducing a new attribute.


>
> 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
> "Amazing Apps with Web Technologies"
>
>
>


-- 
www.sencha.com
"Amazing Apps with Web Technologies"

Received on Tuesday, 5 November 2013 08:13:12 UTC