SVG filters, the final frontier in theming.

Discuss application theming and theme development.
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

SVG filters, the final frontier in theming.

Post by patrickjdempsey »

One thing I've noticed over the years is that no-one is using SVG filters to change the colors of icons. I've often wondered why because it just seems like a complete no-brainer. Even Firefox default theme has for years slogged along with two different Windows themes apparently mostly for the purpose of having half of the icons be a different color.

I have myself been totally confused by SVG masks and filters. They are always presented in a completely obtuse way, with too many complications and ridiculous extra flourishes to impress. So I decided to take the code from Firefox OSX used to make all icons black, simplify the heck out of it and get it to just change icon colors. Here is a sample of what I've learned, using the feColorMatrix:matrix model:

Basic SVG:

Code: Select all

<svg xmlns="http://www.w3.org/2000/svg" height="0">
  <filter id="green"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.0  0.0  0.0  0.0
              0.3  0.8  0.3  0.0  0.0
              0.0  0.0  0.3  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>
</svg>


Basic CSS:

Code: Select all

#back-button:not([disabled="true"]) > .toolbarbutton-icon, 
#forward-button:not([disabled="true"]) > .toolbarbutton-icon {
  filter: url(chrome://customskin/skin/filters.svg#green)!important;
}


The color Matrix works like this (roughly): each value in the matrix represents an RGBA value from 0 to 1 respresenting percentages. In it's most basic sense the grid is this:

R 0 0 0 0
0 G 0 0 0
0 0 B 0 0
0 0 0 A 0

Modifiying the grid outside of the RGBA positions results in greater saturation, but honestly I don't really understand how it works. It's a brilliant example of advanced mathematics stuffed into web code for no apparent reason other than the people coming up with these standards must be EXCEPTIONALLY bored. Anyway, matrix filter has the advantage of being able to force grayscale images into color. There are other basic methods available as well:

saturate: de-saturates an image by a value from 0 to 1:
<feColorMatrix type="saturate" in="SourceGraphic" values = "0.5"/>

hueRotate: shifts the color of the image in degrees around the Hue circle. This would be a simple way to change a green icon to blue... note that it shifts *all* hues by the amount of degrees. It also isn't any good for forcing grayscale icons into a color, because it's only shifting existing hues:
<feColorMatrix type="hueRotate" in="SourceGraphic" values = "175"/>

Pretty much everything else in SVG begins to get immensely complicated and my brain starts to get fuzzy. But these three basic bits are enough to accomplish quite a few interesting things in themes. I'm building a sample theme that shows off matrix filtering.
Last edited by patrickjdempsey on April 22nd, 2014, 6:46 pm, edited 2 times in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
mcdavis
Posts: 3195
Joined: December 9th, 2005, 5:51 am

Re: SVG filters, the final frontier in theming.

Post by mcdavis »

Awesome write-up, I love it. :)
Theme Development is Radical Participation.
NNL Beta Builds for Current and Up-coming Firefox
Dear User: Your Help is Needed
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

A new discovery... with the matrix, when the odd values are 0, there is color bleed on trasparent areas. Turning all of those values to 0.3 cleans it up a bit and allows blacks to be black, for instance this renders a nice green:

Code: Select all

    values = "0.4  0.3  0.3  0.0  0.0
              0.4  0.8  0.3  0.0  0.0
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
Last edited by patrickjdempsey on August 20th, 2012, 1:39 pm, edited 1 time in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

The sample theme will appear here:
https://addons.mozilla.org/en-US/firefo ... vg-colors/

At a whopping 2KB this has got to officially be the smallest possible theme that actually does something.
Last edited by patrickjdempsey on February 7th, 2014, 1:12 am, edited 1 time in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

Started going through my color filters and have begun building the beginnings of a library. This is my current filters.svg file:

Code: Select all

<svg xmlns="http://www.w3.org/2000/svg" height="0">

    <!--* This Source Code Form is subject to the terms of the Mozilla Public
     * License, v. 2.0. If a copy of the MPL was not distributed with this
     * file, You can obtain one at http://mozilla.org/MPL/2.0/. *-->

    <!-- filters created by: patrickjdempsey -->

  <!-- **************  Matrix Filter Library ******************** -->
 
  <!-- Red -->
  <filter id="matrix-r"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.8  0.3  0.3  0.0  0.16
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Poppy -->
  <filter id="matrix-rry"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.9  0.3  0.3  0.0  0.16
              0.3  0.55 0.3  0.0  0.02
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>
 
  <!-- Orange -->
  <filter id="matrix-ry"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.16
              0.3  0.7  0.3  0.0  0.04
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Gold -->
  <filter id="matrix-ryy"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.16
              0.3  0.85 0.3  0.0  0.06
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Yellow -->   
  <filter id="matrix-y"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.16
              0.3  1.0  0.3  0.0  0.08
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>   

  <!-- Citron -->
  <filter id="matrix-yyg"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.85 0.3  0.3  0.0  0.12
              0.3  1.0  0.3  0.0  0.06
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Chartreuse -->   
  <filter id="matrix-yg"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.7  0.3  0.3  0.0  0.08
              0.3  1.0  0.3  0.0  0.04
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Lime -->
  <filter id="matrix-ygg"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.55 0.3  0.3  0.0  0.04
              0.3  1.0  0.3  0.0  0.02
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Green -->     
  <filter id="matrix-g"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  1.0  0.3  0.0  0.0
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Leaf -->
  <filter id="matrix-ggc"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  1.0  0.3  0.0  0.0
              0.3  0.3  0.55 0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Seafoam -->
  <filter id="matrix-gc"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  1.0  0.3  0.0  0.0
              0.3  0.3  0.7  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Turquoise -->
  <filter id="matrix-gcc"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  1.0  0.3  0.0  0.0
              0.3  0.3  0.85 0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>
 
  <!-- Cyan -->     
  <filter id="matrix-c"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  1.0  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Sky -->
  <filter id="matrix-ccb"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  0.85 0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Azure -->
  <filter id="matrix-cb"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  0.7  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Royal -->
  <filter id="matrix-cbb"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  0.55 0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Blue -->     
  <filter id="matrix-b"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Indigo -->
  <filter id="matrix-bbm"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.55 0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Violet -->
  <filter id="matrix-bm"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.7  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Purple -->
  <filter id="matrix-bmm"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "0.85 0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Magenta -->     
  <filter id="matrix-m"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  1.0  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Fuchsia -->
  <filter id="matrix-mmr"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  0.85 0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>   

  <!-- Rose -->
  <filter id="matrix-mr"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  0.7  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>

  <!-- Crimson -->
  <filter id="matrix-mrr"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="matrix" in="SourceGraphic"
    values = "1.0  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.0
              0.3  0.3  0.55 0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>
 
</svg>


This is a 24-color palette based equal-mixing of RGB colors into quartenaries. UI colors are often not "pure" RGB colors, but mixtures that are closer to what humans interpret as the "true" colors. The common "green" used in Firefox for instance is more of an Lime-Green (one part red to eight parts green) the "blue" is more of a Royal (one part green to eight parts blue). I will probably end up naming the colors within the file, but this gives some idea. Note that there are no "official" color names for Tertiary and Quartenary colors, these are just approximations based on color names on Wikipedia. Many of the cyanish and magentaish colors are really subjective: http://en.wikipedia.org/wiki/List_of_colors

matrix-r = Red
matrix-rry = Poppy
matrix-ry = Orange
matrix-ryy = Gold
matrix-y = Yellow
matrix-yyg = Citron
matrix-yg = Chartreuse
matrix-ygg = Lime

matrix-g = Green
matrix-ggc = Leaf
matrix-gc = Seafoam
matrix-gcc = Turquoise
matrix-c = Cyan
matrix-ccb = Deep Sky
matrix-cb = Azure
matrix-cbb = Royal

matrix-b = Blue
matrix-bbm = Indigo
matrix-bm = Violet
matrix-bmm = Purple
matrix-m = Magenta
matrix-mmr = Fuchsia
matrix-mr = Rose
matrix-mrr = Crimson
Last edited by patrickjdempsey on February 6th, 2014, 7:35 pm, edited 9 times in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

So a really pretty fun part of this is that any theme that contains this library could potentially be dramatically changed with only a few lines of code. For instance, if you throw this in your userChrome, you can make a theme with this library use a color scheme similar to the old Netscape 9 theme, even for 3rd party toolbarbuttons like AdBlockPlus!:

Code: Select all

toolbar toolbarbutton.toolbarbutton-1:not([disabled="true"]) .toolbarbutton-icon { 
 filter: url(chrome://customskin/skin/filters.svg#matrix-gcc)!important;
}


Note that you cannot apply multiple filters onto one image. A new filter wipes out the old filter. However, you can apply a second filter to an element one level higher in the DOM and change the underlying layer. So in order to apply a second filter onto all of the toolbarbuttons we could just choose the next level up:

Code: Select all

toolbar toolbarbutton.toolbarbutton-1 { 
 filter: url(chrome://customskin/skin/filters.svg#desat-6)!important;
}


It *IS* possible to layer multiple filters from within the SVG file itself by using feComposite, but not from CSS.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

HMMMMM.... apparently Webkit browsers already have a built-in filter library, too bad Mozilla hasn't even joined that party in a prefixed sense: https://developer.mozilla.org/en-US/docs/CSS/filter

The nice thing about this article is that it includes the actual filters used in Webkit, so we can just float them into our own library. These examples are probably the cleanest examples of feComponentTransfer filter I've seen anywhere online. (As always I wish MDN's docs where better cross-linked). Of course unfortunately the most interesting examples... saturate and sepia are missing the filter references.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

OK, I've made some headway in understanding feColorMatrix. This is pitifully documented. My discovery is that the 5th column is saturation. So it works something like this:

R 0 0 0 S
0 G 0 0 S
0 0 B 0 S
0 0 0 A 0

Except you don't have to create colors using the inner part of the matrix, you can leave the inner part "neutral" to describe the brightness and contrast of the image, and use the saturation column to describe the color. So in my examples in order to bring the nearly black Firefox default icons up to a tintable value I use this pattern... the 0.3's for some reason keep the "empty" part of the icon from having color:

0.4 0.3 0.3
0.3 0.4 0.3
0.3 0.3 0.4

The alpha rows and columns define threshholds for alpha. Setting them at zero for the colors allows each channel to have absolute transparency. If you use a number in the alpha row or columns it sets a bottom limit for that color channel. You could use this to completely remove transparency from an image, but for most purposes you will want to leave them at 0. The bottom corner, alpha/alpha, is the overall transparency of the whole image, which normally you would leave at 1. (Since this can be done more efficiently with good old CSS opacity).

To generate color, I use the saturation column. Let's say I want to generate a nice orange. Since orange is twice as much Red as Green I just bump up the saturation on those channels by that ratio:

0.4 0.3 0.3 0.0 0.4
0.3 0.4 0.3 0.0 0.2
0.3 0.3 0.4 0.0 0.0
0.0 0.0 0.0 1.0 0.0

Note that in my experience saturation numbers above 0.5 are ridiculous. If you throw out the 0-1 scale and use a 0-0.5 scale you can generate very nice colors.

IMO this is dramatically easier and more predictable than adjusting the center of the matrix because those simultaneously effect hue, saturation, and brightness. I do realize that saturation has an impact of human experience of brightness, but it's a little easier to control one dial instead of three at the same time.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

Oh, and despite what I had previously believed, feColorMatrix does NOT completely reset the color of an image, but shifts them. In order to take a color image and make it solidly another color, you would need to desaturate it first. Fortunately that only requires one extra line per filter:

Code: Select all

  <filter id="matrix-g"
          color-interpolation-filters="sRGB"
          filterUnits="objectBoundingBox"
          x="0" y="0" width="100%" height="100%">
    <feColorMatrix type="saturate" in="SourceGraphic" values = "0" result="A" />
    <feColorMatrix type="matrix" in="A"
    values = "0.4  0.3  0.3  0.0  0.0
              0.3  0.4  0.3  0.0  0.3
              0.3  0.3  0.4  0.0  0.0
              0.0  0.0  0.0  1.0  0.0"
    />
  </filter>


I did experiment with changing sRGB color space to RGB and found that it blocked up the values badly with most filter sets, resulting in low tonal range.

P.S. Excuse the technical nature of these posts... color theory is something of a passion of mine, so getting a strong grasp of how this all works is important to me.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

Great News Themers! I'd like to introduce you to what at first glance looks like a terribly confusing filter primative: feComponentTransfer:table. Basically what happens when you use this filter is that it divides each color into equal intensity ranges based on the number of values you have set. But let's not get all complicated. We don't need 5 values for each color. We only need two values: The first value represents the "black" point (floor) and the second value represents the "white" point (ceiling). Just like on a HISTOGRAM! The "normal" range is 0 to 1 representing 0 to 100%. Using this very basic setup we can control Contrast and Lightness... either separately, or at the same time. I won't bore you with more talking but instead give some examples:

Here's a filter that does nothing. Why does it do nothing? Because it's remapping the black point to 0% and the white point to 100%:

Code: Select all

  <filter id="normal"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0 1"/>
      <feFuncG type="table" tableValues="0 1"/>
      <feFuncB type="table" tableValues="0 1"/>
    </feComponentTransfer>
  </filter>


Here's a filter that inverts the image. Why? Because it remaps the black point to 100% and the white point to 0%:

Code: Select all

  <filter id="invert"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="1 0"/>
      <feFuncG type="table" tableValues="1 0"/>
      <feFuncB type="table" tableValues="1 0"/>
    </feComponentTransfer>
  </filter>


This filter lightens all values by moving the black point (floor) up to 50%, and the mid point up to 75%. Notice that it is compressing tonal range by 50% so you also lose contrast:

Code: Select all

  <filter id="floorlighten"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0.5 1"/>
      <feFuncG type="table" tableValues="0.5 1"/>
      <feFuncB type="table" tableValues="0.5 1"/>
    </feComponentTransfer>
  </filter>


This filter darkens all values by moving the white point (ceiling) down to 50%, and the mid point down to 25%. Again, we are losing tonal range and contrast:

Code: Select all

  <filter id="ceilingdarken"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0 0.5"/>
      <feFuncG type="table" tableValues="0 0.5"/>
      <feFuncB type="table" tableValues="0 0.5"/>
    </feComponentTransfer>
  </filter>


This is a true lighten filter which moves both the black point and the white point up to 50%, and the mid point up to 100%. This will "clip" all values over 100% to white.

Code: Select all

  <filter id="lighten"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0.5 1.5"/>
      <feFuncG type="table" tableValues="0.5 1.5"/>
      <feFuncB type="table" tableValues="0.5 1.5"/>
    </feComponentTransfer>
  </filter>


This is a true darken filter which moves the white point and black point down to 50%, and the mid point down to 0%. Note that you use negative values to go below 0%. Again, this will clip all values below 0% to black.

Code: Select all

  <filter id="darken"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="-0.5 0.5"/>
      <feFuncG type="table" tableValues="-0.5 0.5"/>
      <feFuncB type="table" tableValues="-0.5 0.5"/>
    </feComponentTransfer>
  </filter>


This filter reduces overall contrast but keeps the middle point at 50%:

Code: Select all

  <filter id="contrast-"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0.25 0.75"/>
      <feFuncG type="table" tableValues="0.25 0.75"/>
      <feFuncB type="table" tableValues="0.25 0.75"/>
    </feComponentTransfer>
  </filter>


This filter raises overall contrast but keeps the middle point at 50%. Note that you use negative values to go below 0% and values over 1 to go above 100%:

Code: Select all

  <filter id="contrast+"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="-0.25 1.25"/>
      <feFuncG type="table" tableValues="-0.25 1.25"/>
      <feFuncB type="table" tableValues="-0.25 1.25"/>
    </feComponentTransfer>
  </filter>


The four rules:

If Value2 minus Value1 is less than 1: you are lowering contrast.

If Value2 minus Value1 is greater than 1: you are raising contrast.

If the midpoint between Value1 and Value2 is less than 0.5: you are darkening.

If the midpoint between Value1 and Value2 is greater than 0.5: you are lightening.


How freaking easy is THAT? If you are really Histogram savvy, you add a third point in the middle to do Gamma control. And if you are a really Color Curves savvy, you will realize you can use this method for doing complicated hue shifts, removing one color channel, etc. I'm not that savvy. I like things to be SIMPLE. Speaking of simple... we can also use our new buddy to control the Alpha channel and create a simple opacity filter. I've combined this with a desaturation filter so we can use it to simulate the "disabled" state in most Mozilla applications.

We are remapping 0% Alpha (floor) to 0%, and 100% Alpha (ceiling) to 40%... which is the same as applying a 40% opacity in CSS or Photoshop:

Code: Select all

   <filter id="disabled"
          color-interpolation-filters="sRGB">
    <feColorMatrix type="saturate" values = "0.0"/>
    <feComponentTransfer>
      <feFuncA type="table" tableValues="0 0.4"/>
    </feComponentTransfer>
   </filter> 


Now if you are reading and comprehending this, and remembering your process for building icon sets for your Mozilla themes, you should be immediately struck by the fact that all of those repetitive actions in Photoshop and all of those icon templates and all of those image-region codes are now rendered utterly and totally useless. You are welcome.

P.S. if you really insist on documentation, you can find it here, but I'm going to warn you, they go straight into wacky world and ignore these simple methods!
http://docs.webplatform.org/wiki/svg/el ... ntTransfer
Last edited by patrickjdempsey on February 6th, 2014, 4:19 pm, edited 11 times in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

Well heckfire. I said I wasn't going to do Gamma but here's some Gamma anyway:


Lighten the mid tones but preserve black:

Code: Select all

  <filter id="gamma+"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0 0.66 1"/>
      <feFuncG type="table" tableValues="0 0.66 1"/>
      <feFuncB type="table" tableValues="0 0.66 1"/>
    </feComponentTransfer>
  </filter>


Darken the mid tones but preserve white:

Code: Select all

  <filter id="gamma-"
          color-interpolation-filters="sRGB">
    <feComponentTransfer>
      <feFuncR type="table" tableValues="0 0.33 1"/>
      <feFuncG type="table" tableValues="0 0.33 1"/>
      <feFuncB type="table" tableValues="0 0.33 1"/>
    </feComponentTransfer>
  </filter>
Last edited by patrickjdempsey on February 6th, 2014, 4:16 pm, edited 2 times in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

And lastly, because I'm a visual person, here is an example of adding contrast and lightness at the same time as a Histogram chart. First here's a chart showing the default values:

Code: Select all

_ _ _ _ _ 0 _ _ _ _ 0.5 _ _ _ _ 1 _ _ _ _ _
          ^          ^          ^
         (B)        (M)        (W)         


Now lets set our Black and White points to get 20% more contrast, but centered:

Code: Select all

_ _ _-0.2 _ | _ _ _ _ 0.5 _ _ _ _ | _ 1.2 _ _ _
       ^               ^               ^
      (B)             (M)             (W)         


And then shift those to be 10% lighter:

Code: Select all

_ _ _ _-0.1 | _ _ _ _ _ 0.6 _ _ _ | _ _ 1.3 _ _
         ^               ^               ^
        (B)             (M)             (W)       


That makes for a sort of exaggerated "hover" style. Fun huh? So here are the filters I built which I think match pretty well with most classic Firefox and SeaMonkey themes using (basically) the values I've been using for contrast and lightness for many years now:

Code: Select all

    <filter id="hover"
            color-interpolation-filters="sRGB">
      <feComponentTransfer>
        <feFuncR type="table" tableValues="-0.05 1.15"/>
        <feFuncG type="table" tableValues="-0.05 1.15"/>
        <feFuncB type="table" tableValues="-0.05 1.15"/>
      </feComponentTransfer>
    </filter>

    <filter id="active"
            color-interpolation-filters="sRGB">
      <feComponentTransfer>
        <feFuncR type="table" tableValues="-0.3 0.9"/>
        <feFuncG type="table" tableValues="-0.3 0.9"/>
        <feFuncB type="table" tableValues="-0.3 0.9"/>
      </feComponentTransfer>
    </filter>

    <filter id="disabled"
          color-interpolation-filters="sRGB">
      <feColorMatrix type="saturate" values = "0.0"/>
      <feComponentTransfer>
        <feFuncA type="table" tableValues="0 0.4"/>
      </feComponentTransfer>
    </filter> 


And an example in CSS:

Code: Select all

#my-button:not([disabled]):hover .toolbarbutton-icon { 
  filter: url(chrome://mytheme/skin/filters.svg#hover);
}
#my-button[open="true"] .toolbarbutton-icon,
#my-button:not([disabled]):active .toolbarbutton-icon {
  filter: url(chrome://mytheme/skin/filters.svg#active);
}
#my-button[disabled=true] .toolbarbutton-icon {
  filter: url(chrome://mytheme/skin/filters.svg#disabled);
}


And what that looks like:
Image
Last edited by patrickjdempsey on February 6th, 2014, 7:23 pm, edited 1 time in total.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

So here is a fairly large library of SVG filters for a variety of cases. In all examples, the values are in percentages of increase or decrease. For all filters, values are available in 1/10ths, 1/4ths and 1/3rds, expressed as percentages.

Here are the basic filter names and what they do:

contrast+% : black and white points are stretched until 100% where all values are black, white, or pure hues
contrast-% : black and white points are compressed until 100% where all values are 50% grey

brightness+% : black and white points are raised, whites are clipped until 100% where all values are white
brightness-% : black and white points are lowered, blacks are clipped until 100% where all values are black

floor+% : black points are raised and values compressed until 100% where all values are white
cieling-% : white points are lowered and values compressed until 100% where all values are black

gamma+% : midpoint is raised until 100% where all values over the midpoint are compressed to white
gamma-% : midpoint is lowered until 100% where all values under the midpoint are compressed to black

desat_% : saturation is lowered until 100% where all values are greyscale

Values available for all filters: 10, 20, 25, 30, 33, 40, 50, 60, 66, 70, 75, 80, 90
Note that only desat actually has a filter available for 100% because all other filters create totally flat images at 100%.

Code: Select all

<svg height="0" xmlns="http://www.w3.org/2000/svg">
 
  <!--* This Source Code Form is subject to the terms of the Mozilla Public
   * License, v. 2.0. If a copy of the MPL was not distributed with this
   * file, You can obtain one at http://mozilla.org/MPL/2.0/. *-->

  <!-- filters created by: patrickjdempsey -->   
 
     <!-- **************  Contrast Added Filter Library **************  -->
     
        <filter id="contrast+10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.1 1.1"/>
            <feFuncG type="table" tableValues="-0.1 1.1"/>
            <feFuncB type="table" tableValues="-0.1 1.1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast+20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.2 1.2"/>
            <feFuncG type="table" tableValues="-0.2 1.2"/>
            <feFuncB type="table" tableValues="-0.2 1.2"/>
          </feComponentTransfer>
        </filter>   
       
        <filter id="contrast+25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.25 1.25"/>
            <feFuncG type="table" tableValues="-0.25 1.25"/>
            <feFuncB type="table" tableValues="-0.25 1.25"/>
          </feComponentTransfer>
        </filter>
               
        <filter id="contrast+30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.3 1.3"/>
            <feFuncG type="table" tableValues="-0.3 1.3"/>
            <feFuncB type="table" tableValues="-0.3 1.3"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast+33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.333 1.333"/>
            <feFuncG type="table" tableValues="-0.333 1.333"/>
            <feFuncB type="table" tableValues="-0.333 1.333"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast+40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.4 1.4"/>
            <feFuncG type="table" tableValues="-0.4 1.4"/>
            <feFuncB type="table" tableValues="-0.4 1.4"/>
          </feComponentTransfer>
        </filter>   
       
        <filter id="contrast+50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.5 1.5"/>
            <feFuncG type="table" tableValues="-0.5 1.5"/>
            <feFuncB type="table" tableValues="-0.5 1.5"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast+60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.6 1.6"/>
            <feFuncG type="table" tableValues="-0.6 1.6"/>
            <feFuncB type="table" tableValues="-0.6 1.6"/>
          </feComponentTransfer>
        </filter>   

        <filter id="contrast+66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.666 1.666"/>
            <feFuncG type="table" tableValues="-0.666 1.666"/>
            <feFuncB type="table" tableValues="-0.666 1.666"/>
          </feComponentTransfer>
        </filter>
             
        <filter id="contrast+70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.7 1.7"/>
            <feFuncG type="table" tableValues="-0.7 1.7"/>
            <feFuncB type="table" tableValues="-0.7 1.7"/>
          </feComponentTransfer>
        </filter>   
       
        <filter id="contrast+75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.75 1.75"/>
            <feFuncG type="table" tableValues="-0.75 1.75"/>
            <feFuncB type="table" tableValues="-0.75 1.75"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast+80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.8 1.8"/>
            <feFuncG type="table" tableValues="-0.8 1.8"/>
            <feFuncB type="table" tableValues="-0.8 1.8"/>
          </feComponentTransfer>
        </filter>   
       
        <filter id="contrast+90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.9 1.9"/>
            <feFuncG type="table" tableValues="-0.9 1.9"/>
            <feFuncB type="table" tableValues="-0.9 1.9"/>
          </feComponentTransfer>
        </filter>     
       
   <!-- **************  Contrast Reduced Filter Library **************  -->   
           
        <filter id="contrast-10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.05 0.95"/>
            <feFuncG type="table" tableValues="0.05 0.95"/>
            <feFuncB type="table" tableValues="0.05 0.95"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast-20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.1 0.9"/>
            <feFuncG type="table" tableValues="0.1 0.9"/>
            <feFuncB type="table" tableValues="0.1 0.9"/>
          </feComponentTransfer>
        </filter>

        <filter id="contrast-25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.125 0.875"/>
            <feFuncG type="table" tableValues="0.125 0.875"/>
            <feFuncB type="table" tableValues="0.125 0.875"/>
          </feComponentTransfer>
        </filter>
               
        <filter id="contrast-30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.15 0.85"/>
            <feFuncG type="table" tableValues="0.15 0.85"/>
            <feFuncB type="table" tableValues="0.15 0.85"/>
          </feComponentTransfer>
        </filter>

        <filter id="contrast-33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.167 0.833"/>
            <feFuncG type="table" tableValues="0.167 0.833"/>
            <feFuncB type="table" tableValues="0.167 0.833"/>
          </feComponentTransfer>
        </filter>
               
        <filter id="contrast-40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.2 0.8"/>
            <feFuncG type="table" tableValues="0.2 0.8"/>
            <feFuncB type="table" tableValues="0.2 0.8"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast-50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.25 0.75"/>
            <feFuncG type="table" tableValues="0.25 0.75"/>
            <feFuncB type="table" tableValues="0.25 0.75"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast-60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.3 0.7"/>
            <feFuncG type="table" tableValues="0.3 0.7"/>
            <feFuncB type="table" tableValues="0.3 0.7"/>
          </feComponentTransfer>
        </filter>

        <filter id="contrast-66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.333 0.666"/>
            <feFuncG type="table" tableValues="0.333 0.666"/>
            <feFuncB type="table" tableValues="0.333 0.666"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="contrast-70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.35 0.65"/>
            <feFuncG type="table" tableValues="0.35 0.65"/>
            <feFuncB type="table" tableValues="0.35 0.65"/>
          </feComponentTransfer>
        </filter>

        <filter id="contrast-75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.375 0.625"/>
            <feFuncG type="table" tableValues="0.375 0.625"/>
            <feFuncB type="table" tableValues="0.375 0.625"/>
          </feComponentTransfer>
        </filter>
               
        <filter id="contrast-80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.4 0.6"/>
            <feFuncG type="table" tableValues="0.4 0.6"/>
            <feFuncB type="table" tableValues="0.4 0.6"/>
          </feComponentTransfer>
        </filter>

        <filter id="contrast-90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.45 0.55"/>
            <feFuncG type="table" tableValues="0.45 0.55"/>
            <feFuncB type="table" tableValues="0.45 0.55"/>
          </feComponentTransfer>
        </filter>

     <!-- **************  Brightness Lighten Filter Library **************  -->
     
        <filter id="brightness+10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.1 1.1"/>
            <feFuncG type="table" tableValues="0.1 1.1"/>
            <feFuncB type="table" tableValues="0.1 1.1"/>
          </feComponentTransfer>
        </filter>

        <filter id="brightness+20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.2 1.2"/>
            <feFuncG type="table" tableValues="0.2 1.2"/>
            <feFuncB type="table" tableValues="0.2 1.2"/>
          </feComponentTransfer>
        </filter>
               
        <filter id="brightness+25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.25 1.25"/>
            <feFuncG type="table" tableValues="0.25 1.25"/>
            <feFuncB type="table" tableValues="0.25 1.25"/>
          </feComponentTransfer>
        </filter>
     
         <filter id="brightness+30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.3 1.3"/>
            <feFuncG type="table" tableValues="0.3 1.3"/>
            <feFuncB type="table" tableValues="0.3 1.3"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness+33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.333 1.333"/>
            <feFuncG type="table" tableValues="0.333 1.333"/>
            <feFuncB type="table" tableValues="0.333 1.333"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness+40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.4 1.4"/>
            <feFuncG type="table" tableValues="0.4 1.4"/>
            <feFuncB type="table" tableValues="0.4 1.4"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness+50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.5 1.5"/>
            <feFuncG type="table" tableValues="0.5 1.5"/>
            <feFuncB type="table" tableValues="0.5 1.5"/>
          </feComponentTransfer>
        </filter>

     
        <filter id="brightness+60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.6 1.6"/>
            <feFuncG type="table" tableValues="0.6 1.6"/>
            <feFuncB type="table" tableValues="0.6 1.6"/>
          </feComponentTransfer>
        </filter>

        <filter id="brightness+66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.666 1.666"/>
            <feFuncG type="table" tableValues="0.666 1.666"/>
            <feFuncB type="table" tableValues="0.666 1.666"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="brightness+70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.7 1.7"/>
            <feFuncG type="table" tableValues="0.7 1.7"/>
            <feFuncB type="table" tableValues="0.7 1.7"/>
          </feComponentTransfer>
        </filter>

        <filter id="brightness+75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.75 1.75"/>
            <feFuncG type="table" tableValues="0.75 1.75"/>
            <feFuncB type="table" tableValues="0.75 1.75"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="brightness+80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.8 1.8"/>
            <feFuncG type="table" tableValues="0.8 1.8"/>
            <feFuncB type="table" tableValues="0.8 1.8"/>
          </feComponentTransfer>
        </filter>   
               
        <filter id="brightness+90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.9 1.9"/>
            <feFuncG type="table" tableValues="0.9 1.9"/>
            <feFuncB type="table" tableValues="0.9 1.9"/>
          </feComponentTransfer>
        </filter>   
       
 
      <!-- **************  Brightness Darken Filter Library **************  -->   
       
        <filter id="brightness-10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.1 0.9"/>
            <feFuncG type="table" tableValues="-0.1 0.9"/>
            <feFuncB type="table" tableValues="-0.1 0.9"/>
          </feComponentTransfer>
        </filter>

        <filter id="brightness-20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.2 0.8"/>
            <feFuncG type="table" tableValues="-0.2 0.8"/>
            <feFuncB type="table" tableValues="-0.2 0.8"/>
          </feComponentTransfer>
        </filter>
               
        <filter id="brightness-25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.25 0.75"/>
            <feFuncG type="table" tableValues="-0.25 0.75"/>
            <feFuncB type="table" tableValues="-0.25 0.75"/>
          </feComponentTransfer>
        </filter>
     
         <filter id="brightness-30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.3 0.7"/>
            <feFuncG type="table" tableValues="-0.3 0.7"/>
            <feFuncB type="table" tableValues="-0.3 0.7"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness-33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.333 0.666"/>
            <feFuncG type="table" tableValues="-0.333 0.666"/>
            <feFuncB type="table" tableValues="-0.333 0.666"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness-40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.4 0.6"/>
            <feFuncG type="table" tableValues="-0.4 0.6"/>
            <feFuncB type="table" tableValues="-0.4 0.6"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness-50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.5 0.5"/>
            <feFuncG type="table" tableValues="-0.5 0.5"/>
            <feFuncB type="table" tableValues="-0.5 0.5"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness-60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.6 0.4"/>
            <feFuncG type="table" tableValues="-0.6 0.4"/>
            <feFuncB type="table" tableValues="-0.6 0.4"/>
          </feComponentTransfer>
        </filter>

        <filter id="brightness-66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.666 0.333"/>
            <feFuncG type="table" tableValues="-0.666 0.333"/>
            <feFuncB type="table" tableValues="-0.666 0.333"/>
          </feComponentTransfer>
        </filter>
           
        <filter id="brightness-70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.7 0.3"/>
            <feFuncG type="table" tableValues="-0.7 0.3"/>
            <feFuncB type="table" tableValues="-0.7 0.3"/>
          </feComponentTransfer>
        </filter>

        <filter id="brightness-75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.75 0.25"/>
            <feFuncG type="table" tableValues="-0.75 0.25"/>
            <feFuncB type="table" tableValues="-0.75 0.25"/>
          </feComponentTransfer>
        </filter>
           
        <filter id="brightness-80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.8 0.2"/>
            <feFuncG type="table" tableValues="-0.8 0.2"/>
            <feFuncB type="table" tableValues="-0.8 0.2"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="brightness-90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.9 0.1"/>
            <feFuncG type="table" tableValues="-0.9 0.1"/>
            <feFuncB type="table" tableValues="-0.9 0.1"/>
          </feComponentTransfer>
        </filter>

     <!-- **************  Floor Lighten Filter Library **************  -->
     
        <filter id="floor+10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.1 1"/>
            <feFuncG type="table" tableValues="0.1 1"/>
            <feFuncB type="table" tableValues="0.1 1"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="floor+20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.2 1"/>
            <feFuncG type="table" tableValues="0.2 1"/>
            <feFuncB type="table" tableValues="0.2 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.25 1"/>
            <feFuncG type="table" tableValues="0.25 1"/>
            <feFuncB type="table" tableValues="0.25 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.3 1"/>
            <feFuncG type="table" tableValues="0.3 1"/>
            <feFuncB type="table" tableValues="0.3 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.333 1"/>
            <feFuncG type="table" tableValues="0.333 1"/>
            <feFuncB type="table" tableValues="0.333 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.4 1"/>
            <feFuncG type="table" tableValues="0.4 1"/>
            <feFuncB type="table" tableValues="0.4 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.5 1"/>
            <feFuncG type="table" tableValues="0.5 1"/>
            <feFuncB type="table" tableValues="0.5 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.6 1"/>
            <feFuncG type="table" tableValues="0.6 1"/>
            <feFuncB type="table" tableValues="0.6 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.666 1"/>
            <feFuncG type="table" tableValues="0.666 1"/>
            <feFuncB type="table" tableValues="0.666 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.7 1"/>
            <feFuncG type="table" tableValues="0.7 1"/>
            <feFuncB type="table" tableValues="0.7 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.75 1"/>
            <feFuncG type="table" tableValues="0.75 1"/>
            <feFuncB type="table" tableValues="0.75 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.8 1"/>
            <feFuncG type="table" tableValues="0.8 1"/>
            <feFuncB type="table" tableValues="0.8 1"/>
          </feComponentTransfer>
        </filter>     

        <filter id="floor+90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0.9 1"/>
            <feFuncG type="table" tableValues="0.9 1"/>
            <feFuncB type="table" tableValues="0.9 1"/>
          </feComponentTransfer>
        </filter>
       
     <!-- **************  Cieling Darken Filter Library **************  -->
     
        <filter id="cieling-10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.9"/>
            <feFuncG type="table" tableValues="0 0.9"/>
            <feFuncB type="table" tableValues="0 0.9"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.8"/>
            <feFuncG type="table" tableValues="0 0.8"/>
            <feFuncB type="table" tableValues="0 0.8"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.7"/>
            <feFuncG type="table" tableValues="0 0.7"/>
            <feFuncB type="table" tableValues="0 0.7"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.666"/>
            <feFuncG type="table" tableValues="0 0.666"/>
            <feFuncB type="table" tableValues="0 0.666"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.6"/>
            <feFuncG type="table" tableValues="0 0.6"/>
            <feFuncB type="table" tableValues="0 0.6"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.5"/>
            <feFuncG type="table" tableValues="0 0.5"/>
            <feFuncB type="table" tableValues="0 0.5"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.4"/>
            <feFuncG type="table" tableValues="0 0.4"/>
            <feFuncB type="table" tableValues="0 0.4"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.333"/>
            <feFuncG type="table" tableValues="0 0.333"/>
            <feFuncB type="table" tableValues="0 0.333"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.3"/>
            <feFuncG type="table" tableValues="0 0.3"/>
            <feFuncB type="table" tableValues="0 0.3"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.25"/>
            <feFuncG type="table" tableValues="0 0.25"/>
            <feFuncB type="table" tableValues="0 0.25"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.2"/>
            <feFuncG type="table" tableValues="0 0.2"/>
            <feFuncB type="table" tableValues="0 0.2"/>
          </feComponentTransfer>
        </filter>
     
        <filter id="cieling-90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.1"/>
            <feFuncG type="table" tableValues="0 0.1"/>
            <feFuncB type="table" tableValues="0 0.1"/>
          </feComponentTransfer>
        </filter>
       
       
     <!-- **************  gamma Raised Filter Library **************  -->
     
        <filter id="gamma+10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.55 1"/>
            <feFuncG type="table" tableValues="0 0.55 1"/>
            <feFuncB type="table" tableValues="0 0.55 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.6 1"/>
            <feFuncG type="table" tableValues="0 0.6 1"/>
            <feFuncB type="table" tableValues="0 0.6 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.625 1"/>
            <feFuncG type="table" tableValues="0 0.625 1"/>
            <feFuncB type="table" tableValues="0 0.625 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.65 1"/>
            <feFuncG type="table" tableValues="0 0.65 1"/>
            <feFuncB type="table" tableValues="0 0.65 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.666 1"/>
            <feFuncG type="table" tableValues="0 0.666 1"/>
            <feFuncB type="table" tableValues="0 0.666 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.7 1"/>
            <feFuncG type="table" tableValues="0 0.7 1"/>
            <feFuncB type="table" tableValues="0 0.7 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.75 1"/>
            <feFuncG type="table" tableValues="0 0.75 1"/>
            <feFuncB type="table" tableValues="0 0.75 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.8 1"/>
            <feFuncG type="table" tableValues="0 0.8 1"/>
            <feFuncB type="table" tableValues="0 0.8 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.833 1"/>
            <feFuncG type="table" tableValues="0 0.833 1"/>
            <feFuncB type="table" tableValues="0 0.833 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.85 1"/>
            <feFuncG type="table" tableValues="0 0.85 1"/>
            <feFuncB type="table" tableValues="0 0.85 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+75"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.875 1"/>
            <feFuncG type="table" tableValues="0 0.875 1"/>
            <feFuncB type="table" tableValues="0 0.875 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.9 1"/>
            <feFuncG type="table" tableValues="0 0.9 1"/>
            <feFuncB type="table" tableValues="0 0.9 1"/>
          </feComponentTransfer>
        </filter>
       
        <filter id="gamma+90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.95 1"/>
            <feFuncG type="table" tableValues="0 0.95 1"/>
            <feFuncB type="table" tableValues="0 0.95 1"/>
          </feComponentTransfer>
        </filter>

     <!-- **************  gamma Lowered Filter Library **************  -->
     
        <filter id="gamma-10"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.45 1"/>
            <feFuncG type="table" tableValues="0 0.45 1"/>
            <feFuncB type="table" tableValues="0 0.45 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-20"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.4 1"/>
            <feFuncG type="table" tableValues="0 0.4 1"/>
            <feFuncB type="table" tableValues="0 0.4 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-25"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.375 1"/>
            <feFuncG type="table" tableValues="0 0.375 1"/>
            <feFuncB type="table" tableValues="0 0.375 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-30"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.35 1"/>
            <feFuncG type="table" tableValues="0 0.35 1"/>
            <feFuncB type="table" tableValues="0 0.35 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-33"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.333 1"/>
            <feFuncG type="table" tableValues="0 0.333 1"/>
            <feFuncB type="table" tableValues="0 0.333 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-40"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.3 1"/>
            <feFuncG type="table" tableValues="0 0.3 1"/>
            <feFuncB type="table" tableValues="0 0.3 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-50"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.25 1"/>
            <feFuncG type="table" tableValues="0 0.25 1"/>
            <feFuncB type="table" tableValues="0 0.25 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-60"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.2 1"/>
            <feFuncG type="table" tableValues="0 0.2 1"/>
            <feFuncB type="table" tableValues="0 0.2 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-66"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.167 1"/>
            <feFuncG type="table" tableValues="0 0.167 1"/>
            <feFuncB type="table" tableValues="0 0.167 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-70"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.15 1"/>
            <feFuncG type="table" tableValues="0 0.15 1"/>
            <feFuncB type="table" tableValues="0 0.15 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-80"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.1 1"/>
            <feFuncG type="table" tableValues="0 0.1 1"/>
            <feFuncB type="table" tableValues="0 0.1 1"/>
          </feComponentTransfer>
        </filter>

        <filter id="gamma-90"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="0 0.05 1"/>
            <feFuncG type="table" tableValues="0 0.05 1"/>
            <feFuncB type="table" tableValues="0 0.05 1"/>
          </feComponentTransfer>
        </filter>

     <!-- **************  Desaturate Filter Library **************  -->

        <filter id="desat_10"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.9"/>
        </filter> 

        <filter id="desat_20"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.8"/>
        </filter> 
 
        <filter id="desat_25"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.75"/>
        </filter>   

        <filter id="desat_30"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.7"/>
        </filter>   

        <filter id="desat_33"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.666"/>
        </filter>   

        <filter id="desat_40"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.6"/>
        </filter>   

        <filter id="desat_50"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.5"/>
        </filter>   

        <filter id="desat_60"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.4"/>
        </filter>   

        <filter id="desat_66"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.333"/>
        </filter> 

        <filter id="desat_70"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.3"/>
        </filter>   

        <filter id="desat_75"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.25"/>
        </filter>   

        <filter id="desat_80"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.2"/>
        </filter>   

        <filter id="desat_90"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.1"/>
        </filter> 

        <filter id="desat_100"
                color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.0"/>
        </filter>   

  <!-- ************** Random Filters ******************-->


        <filter id="invert"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="1 0"/>
            <feFuncG type="table" tableValues="1 0"/>
            <feFuncB type="table" tableValues="1 0"/>
          </feComponentTransfer>
        </filter>

        <filter id="hover"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.05 1.15"/>
            <feFuncG type="table" tableValues="-0.05 1.15"/>
            <feFuncB type="table" tableValues="-0.05 1.15"/>
          </feComponentTransfer>
        </filter>

        <filter id="active"
                color-interpolation-filters="sRGB">
          <feComponentTransfer>
            <feFuncR type="table" tableValues="-0.3 0.9"/>
            <feFuncG type="table" tableValues="-0.3 0.9"/>
            <feFuncB type="table" tableValues="-0.3 0.9"/>
          </feComponentTransfer>
        </filter>

        <filter id="disabled"
              color-interpolation-filters="sRGB">
          <feColorMatrix type="saturate" values = "0.0"/>
          <feComponentTransfer>
            <feFuncA type="table" tableValues="0 0.4"/>
          </feComponentTransfer>
        </filter> 
       
</svg>
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

Well friends, I have just tackled a true monster. For a long while now I've been looking for a way to colorize icons using SVG in a predictable, clean manner, using any color. And by *any* color I mean RGB, RGBA, HSL, HSLA, CSS color names, OS color names, and Mozilla-specific color names. Wouldn't that be swell??? Unfortunately, this has not been easy, or obvious. I present to you my work, in three stages:

My original concept for a colorize filter sounds like it should be ridiculously easy to do: flood the area with a color and blend that color with the graphic. This would probably be a whole heck of a lot easier if the blending methods available in SVG were worth a darn. In Firefox the "multiply" and "darken" modes for feBlend appear to be identical, and the "screen" and "lighten" modes appear to be identical. This is a very sorry state of affairs because ideally either "multiply" or "screen" would do what I want, but doesn't. Tsk.

This is my first "break through" filter.

Code: Select all

  <filter id="colorize_darken_red"
            color-interpolation-filters="sRGB">
       <feFlood flood-color="red" result="A"/>
       <feColorMatrix type="saturate" in="SourceGraphic" values = "0" result="B"/>
       <feBlend mode="darken" in2="A" result="C"/>
       <feComposite in2="SourceGraphic" operator="in" />
  </filter>


What it does in 4 stages:

1. Flood the area with the selected color using feFlood.

2. Convert the original image to greyscale using feColorMatrix type="saturate".

3. Map white in the greyscale image to the flooded color area, preserving blacks, using feBlend mode="darken".

4. Cut out the results of 3 with the original graphic to remove colorized border and background using feComposite.

This makes white = selected color. Not very good unless your selected color is light to begin with. My second version is the same as the first but uses feBlend mode="lighten" to map the flooded color to black and preserve the whites:

Code: Select all

  <filter id="colorize_lighten_red"
            color-interpolation-filters="sRGB">
       <feFlood flood-color="red" result="A"/>
       <feColorMatrix type="saturate" in="SourceGraphic" values = "0" result="B"/>
       <feBlend mode="lighten" in2="A" result="C"/>
       <feComposite in2="SourceGraphic" operator="in" />
  </filter>


This makes black = selected color. Great if your selected color is really dark, but not a good universal tool. So this made me think I need to somehow be able to combine the two methods. After ummm a year and a half of experimentation I've come up with this:

Code: Select all

  <filter id="colorize_super_red"
            color-interpolation-filters="sRGB">
       <feFlood flood-color="red" result="A"/>
       <feColorMatrix type="saturate" in="SourceGraphic" values = "0" result="B"/>
       <feColorMatrix type="luminanceToAlpha" result="C"/>
       <feBlend mode="darken" in2="B" in="A" result="D"/>
       <feBlend mode="lighten" in2="B" in="A" result="E"/>
       <feComposite in2="C" operator="in" result="H"/>
       <feBlend mode="normal" in2="D" result="I"/> 
       <feComposite in2="SourceGraphic" operator="in" />                         
  </filter>


What it does in 8 stages:

1. Flood the area with the selected color using feFlood.

2. Convert the original image to greyscale using feColorMatrix type="saturate".

3. Convert the original image into an alpha mask using feColorMatrix type="luminanceToAlpha".

4. Map white in the greyscale image to the flooded color area, preserving shadows, using feBlend mode="darken".

5. Map black in the greyscale image to the flooded color area, preserving highlights, using feBlend mode="lighten".

6. Cut out the results of 5 with the results of 3 to create a transparent highlight area mask using feComposite.

7. Lay the transparent highlight mask from 6 on top of the shadow results of 4 using feBlend mode="normal".

8. Cut out the results of 7 with the original graphic to remove colorized border and background using feComposite.

So yeah... super simple huh? Anway... there's the dragon laid bare:

Image
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
User avatar
patrickjdempsey
Posts: 23686
Joined: October 23rd, 2008, 11:43 am
Location: Asheville NC
Contact:

Re: SVG filters, the final frontier in theming.

Post by patrickjdempsey »

With SVG filters, there is a built-in desaturation command... confusingly called "saturate". But I believe I have cracked the issue of how to increase saturation using a matrix filter.

To start with, here is a static SVG matrix filter that will output no change:

1.0 0.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0 0.0
0.0 0.0 1.0 0.0 0.0
0.0 0.0 0.0 1.0 0.0

Let's ignore the Alpha and Brightness channels and just talk about the main RGB grid:

1.0 0.0 0.0 R
0.0 1.0 0.0 G
0.0 0.0 1.0 B

Each row represents the actual color channel. Brightness is determined by adding up the three columns in each row:

0.0 + 1.0 + 0.0 = 100% brightness

We can lower saturation and keep the brightness by adding to the "off" channels and subtracting from the "on" channels, as long as they add up to 100%:

0.8 + 0.1 + 0.1
0.1 + 0.8 + 0.1
0.1 + 0.1 + 0.8

Total grayscale is reached at 1/3:

0.33 0.33 0.33
0.33 0.33 0.33
0.33 0.33 0.33

Now, if we inverse the values, we can add saturation and preserve brightness, again, as long as the values add up to 100%:

1.2 -0.1 -0.1
-0.1 1.2 -0.1
-0.1 -0.1 1.2

I don't think there is a really maximum saturation value, but the colors start getting ridiculous after this point:

5.0 -2.0 -2.0
-2.0 5.0 -2.0
-2.0 -2.0 5.0

So here is an example saturation filter:

Code: Select all

  <filter id="sat+20"
          color-interpolation-filters="sRGB">
    <feColorMatrix type="matrix" in="SourceGraphic"
      values = "1.4  -0.2  -0.2  0.0  0.0
                -0.2  1.4  -0.2  0.0  0.0
                -0.2  -0.2  1.4  0.0  0.0
                0.0   0.0   0.0  1.0  0.0"
    />
  </filter>


I am working on making all of this available as a library, but it is kind of a back-burner project at the moment.
Tip of the day: If it has "toolbar" in the name, it's crap.
What my avatar is about: https://addons.mozilla.org/en-US/seamonkey/addon/sea-fox/
Post Reply