-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[filter-effects-2] Add recolor() shorthand #334
Comments
I like this idea! But, there's actually many ways to do recolorization. I have summarized the most used ones below. I also created a CodePen example page, which shows how they affect images. The example page works best with Firefox. I've added a parameter to control the proportion of the conversion. It is called amount. sepia(amount)This is the existing colorization method in CSS shorthands. It preserves black and converts white to yellowish. The amount parameter controls the proportion of the conversion. CSS shorthand tricksThis is a colorization hack made using the existing CSS shorthand filters. Typically, invert(), sepia(), hue-rotate() and saturate() are used. References:
recolor(amount, color)This is the function proposed by the original poster. It colorizes all pixels to the same color. tint(amount, color)Preserves black and converts white to the desired color. This is a bit like sepia(), but uses a user defined color. Alternatively, it could convert black to the desired color and preserve white. References: duotone(amount, color1, color2)This takes two colors. One color for black and one color for white. Intermediate colors get colors between those two. Setting both colors to the same color will give the same result as recolor. References: tritone(amount, color1, color2, color3)This takes three colors. One for highlights (white), one for midtones and one for shadows (black). Setting all colors to the same color will give the same result as recolor. Note: For some reason, midtones affect the #c0c0c0 gray instead of #808080 gray in Firefox. Ideally, #808080 gray should be affected. Note: It is possible to extend tritone for any number of colors. Tritone can be implemented with feComponentTransfer in the table mode and additional colors could just be added to the color table. I don't know if that would be useful.. After Effects has a tritone effect. It seems to affect #808080 gray and gives better results than Firefox. References: Apple Motion: tintApple Motion has a tint filter, which affects only midtones. It seems to be the same as tritone with black, a user defined color and white. Android LightingColorFilterAndroid has a filter to colorize images. It takes two colors. The first one is used for multiplication and the second one for addition, like this:
If colorMultiply is black, then this gives the same result as recolor. This isn't as intuitive as duotone, so I wouldn't like to see this in CSS. References: Layer Color BlendA usual method to colorize images in Photoshop and other image editors is to create a solid color layer in the desired color, place it over the image and then blend the color layer with the image using the "Color" blend mode. The downside is that it also colorizes transparent pixels, so I wouldn't like to see this in CSS. References: SummaryThere's probably also other colorization methods. All other suggestions are welcome! I don't expect to see all these implemented in CSS. I think duotone and tritone would be most useful. They are easy to use and they cover most use cases (recoloring text, icons, photos). Duotone works great for simple icons. Tritone is similar to highlight-midtone-shadow filters in photo editors. |
I like this a lot! So, duotone() and tritone() seem great directly as stated. Useful, easy to understand, good names. For the single-color ones, functionality seems good, but naming is harder. So, tint() technically means "adding white to a base color", lightening it. (And its opposite, "shade", means to darken a color by adding black.) So saying (People do casually use "tint" in these sorts of ways, but it's extremely varied; if we're relying on casual definitions, we can't rely on a meaningful distinction between "tint" and "shade" to distinguish our "shift black towards the color" from "shift white towards the color" functions.) I suggest we avoid the issue entirely by just not providing the single-color functions. People can just write (Unlike the "you can implement duotone() with tritone()" argument, where you need to do some color math to make it happen, this requires no math. You just fill in one of the arguments with "white" or "black". That seems easy enough to make it reasonable to skip on providing a convenience function.) I agree that Apple's "tint" doesn't need a convenience function, as tritone() seems to handle it just fine. I'm not even sure what the Android Lighting thing is doing, semantically. I always look askance at anything trying to add/multiply individual channels; it's smuggling in masking data via color channels in a way that doesn't feel very kosher. I'm not sure what "color blending" is, mathematically, in Photoshop. But that article's examples seems moderately useful? What do you mean by "colorizes transparent pixels" - do they stay transparent, just change their (undetectable) hue? |
Some thoughts: In general, I'm very supportive of adding color effects beyond Thinking of the use cases, I'd recommend a single
The function could also accept a percentage (or number 0-1) for reducing the overall effect (blending with the original colors), equivalent to the parameter to the |
That sounds pretty good to me. I like |
I very much like using a single recolor() or colorize() function for
monotone, duotone and tritone effects. I do think it's important to support
the use case where all colors are set to a target color (monotone) - as in
the SVG Filter implementation proposed rather than scaled. (The behavior
you propose for 1 color value can be duplicated with a duotone where the
white point is set to white.)
…On Thu, May 9, 2019 at 3:54 PM Amelia Bellamy-Royds < ***@***.***> wrote:
Some thoughts:
In general, I'm very supportive of adding color effects beyond sepia() in
the shorthand function. The sepia-saturate-hue-rotate sequence is painful &
imprecise, but I've seen it recommended in multiple tutorials and demos. So
let's make it easier to do better.
Thinking of the use cases, I'd recommend a single recolor() or colorize()
function that accepts 1 to 3 color values:
-
1 color value sets the target value for black pixels in the input.
(White pixels stay white, and all other colors get scaled up by the change
in the black point.) This addresses the common case of applying a “fill”
color to a solid black icon.
-
2 color values set the target black and white points (duotone effect).
-
3 color values set the black, midtone, and white points (tritone
effect)
The function could also accept a percentage (or number 0-1) for reducing
the overall effect (blending with the original colors), equivalent to the
parameter to the sepia() function.
—
You are receiving this because you authored the thread.
Reply to this email directly, view it on GitHub
<#334 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAB325UC773FE2Q37GIUJIDPUSTRNANCNFSM4G37JTIA>
.
--
3 things you can do to help fight climate change: Change, Vote, & Advocate (
http://www.timetochoose.com/)
|
What's the use-case for "set all pixels to this color"? If it's just recoloring icons, as long as they start out black the behavior Amelia proposed will work. |
I can see use cases for @gitmullany's proposal: grey-ing out a multi-color icon for a disabled function or otherwise forcing a multi-color icon to match a theme color. It could also help with progressive enhancement if people are currently using red icons + Basically, this would be equivalent to expanding |
Having an icon of one colour (not necessarily black), and wanting to change it to something else, seems to be a common use case. At least based on Stack Overflow questions. They can always use |
Saturate increases saturation (multiplies it by a scaling factor). For a grayscale image, the saturation is zero; multiplying it by anything still results in zero. On a hue wheel, all pixels are on the central achromatic axis - there is no hue direction that can be amplified. I don't have an opinion on |
I meant
Yes. That was my point also. If you are expected to grayscale the image first, then |
I like the idea of having only one shorthand function. Authors should not be expected to grayscale the image first. It should be part of the shorthand's functionality. Authors don't necessarily know which grayscale values to use for amount values less than 1, such as this: I don't have a strong opinion about the name I think that the single color case should create an image with only one color. I'm not a color expert, but it feels more logical: 1 color -> all pixels get converted to the same color (not two colors, where the other one is black or white) I found out the reason why my CodePen example didn't produce exactly correct results for tritones. I had misspelled the color-interpolation-filters property. I'll update the example when I have more time. |
Based on the preceding comments, can I suggest something along the following lines (I'm not an experienced spec writer - so please treat with appropriate patience/forebearance) Using https://www.w3.org/TR/filter-effects-1/ as the base document: add to Section 6.1 recolor() = recolor( colorA, colorB, colorC ) Applies a monotone, duotone or tritone effect on the input image based on the number of input colors. The monotone effect discards the input image's color channels replacing them with ColorA. The duotone and tritone effects map the luminosity of the input image to new range(s) in each color channel based on the red, green and blue values specified in colorA and colorB (and colorC if present). The markup equivalent of this function is given below. Default value when omitted is opaque black And added to Section 13.1.11
We could express all of this using feComponentTransfer - but since feColorMatrix has been made very fast in existing browsers and feComponentTransfer is generally quite slow - I'm hoping that the single color case can be supported with high performance with minimal work. This might be a misunderstanding of how the implementors approach spec implementation - but I thought I'd suggest it. As this stands, this preserves the alpha channel of the input image. There may be cases where people want to adjust the alpha channel or apply a % effect - is it ok not to expose these capabilities in a shorthand (vs making users write a SVG filter.) |
Is there a reason why you don't want to have amount (to apply a % effect) in the shorthand function? User interfaces often use an animated color fading to change their states between active and inactive. That effect could be created with amount, which can be animated with CSS animations and transitions. SVG filters can't be animated with CSS. Also, the amount parameter would make recolor() similar to the sepia(amount) colorization function. Here are the matrices to calculate the three versions of recolor() with amount to control the proportion of the conversion. If amount is 0, then the original image is shown. If amount is 1, then the recolored version is shown.
The one color case (monotone) is as performant as the version without the amount value:
The two color case (duotone) can be written using feColorMatrix, feComponentTransfer and feComposite. feComposite is used to blend the original image and the colorized image.
It can be optimized to use only feColorMatrix, so it is as performant as the one color case. It requires pre-calculation of the color matrix and then the values are set to feColorMatrix:
The three color case (tritone) can only be written using feColorMatrix, feComponentTransfer and feComposite. It is the same as the non-optimized two color case except feComponentTransfer has three colors:
Here's a new CodePen example with those matrices. The amount parameter has been implemented for all these cases. The example works the best with Firefox and Chrome. All these recolor() shorthand filters operate in the sRGB colorspace, just like the other existing shorthand filters. |
I hadn't put in an amount because these shorthands are transitionable without an amount (I didn't add the spec language for that, but it's in another section). But having an amount seems useful & I think what you're proposing is more flexible. Also, I can't imagine it being much more of an implementation effort. So +1 from me. |
@AmeliaBR Yeah, and looking into some other uses of color-mixing, it looks like things like "just mix a little purple into all of these images, to make them visually match a little more" is a useful thing people do. So yeah, |
A popular request on StackOverflow in the css-filters tag is to use filters to recolor an input to a target color. This is trivial in SVG filters using the fifth column of feColorMatrix. In the absence of a recolor() shorthand in CSS, people are chaining together hue-rotate(), sepia(), invert() and saturate() filters to try to get to an approximation. It's both inefficient and inaccurate given hue-rotate's unfortunate tendency to clip result values.
I would like to propose adding a new CSS filter shorthand - recolor() - that takes a single color value as its argument - to this spec section: https://www.w3.org/TR/filter-effects-1/#ShorthandEquivalents
13.1.11 recolor
The text was updated successfully, but these errors were encountered: