-
-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(CSSHelper): Add CSS filter utilities
- Loading branch information
Showing
4 changed files
with
210 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
105 changes: 105 additions & 0 deletions
105
Sources/Rendering/Core/ColorTransferFunction/CssFilters.d.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/** | ||
* A helper file to transform RGBA points using CSS filters equivalent | ||
* The equivalents of CSS filters using SVG filters can be found here: | ||
* https://www.w3.org/TR/filter-effects-1/#ShorthandEquivalents | ||
* For each SVG filter, you can look for the maths behind it on the same page: | ||
* https://www.w3.org/TR/filter-effects-1/#FilterPrimitivesOverview | ||
* | ||
* For example, the saturate filter equivalent is here: | ||
* https://www.w3.org/TR/filter-effects-1/#saturateEquivalent | ||
* And the maths behind the feColorMatrix of type saturate is here: | ||
* https://www.w3.org/TR/filter-effects-1/#ref-for-attr-valuedef-type-saturate | ||
* | ||
* The transforms are done using matrices of size 5 by 5. They are row major | ||
* as in vtkMath. The vectors representing the RGBA points uses | ||
* [R, G, B, A, 1] vectors, with each channel between 0 and 1. | ||
*/ | ||
|
||
import { Matrix, Vector3 } from "../../../types"; | ||
|
||
export const luminanceWeights: Vector3; | ||
export type FilterMatrix = Matrix; | ||
|
||
/** | ||
* Create a new filter matrix | ||
* This is a 5x5 row major array | ||
* Use applyFilter() function to use it | ||
* It is NOT the identity | ||
*/ | ||
export function getNewFilter(): FilterMatrix; | ||
|
||
/** | ||
* Convert a filter to an identity matrix or create a new identity filter | ||
* @param outFilter If specified, the outFilter is converted to identity filter | ||
*/ | ||
export function getIdentityFilter(outFilter?: FilterMatrix): FilterMatrix; | ||
|
||
/** | ||
* Combine two filters into a single filter | ||
* The order matters | ||
* @param baseFilter The first filter that will be applied | ||
* @param newFilter The second filter that will be applied | ||
* @param outFilter An optional filter that will contain the combined filter | ||
*/ | ||
export function combineFilters(baseFilter: FilterMatrix, newFilter: FilterMatrix, outFilter?: FilterMatrix): FilterMatrix; | ||
|
||
/** | ||
* Apply a filter to a rgb(a) point | ||
* @param filter The filter | ||
* @param r The red channel (between 0 and 1) | ||
* @param g The green channel (between 0 and 1) | ||
* @param b The blue channel (between 0 and 1) | ||
* @param a The optional alpha channel (between 0 and 1), defaults to 1 | ||
* @returns A vector of size 4 [r, g, b, a] | ||
*/ | ||
export function applyFilter(filter: FilterMatrix, r: number, g: number, b: number, a?: number): [number, number, number, number]; | ||
|
||
/** | ||
* A generic linear filter | ||
* See svg equivalent for parameters and a specification | ||
* https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-linear | ||
* @param slope | ||
* @param intercept | ||
* @param outFilter Optional output, a new filter is created if not specified | ||
*/ | ||
export function getLinearFilter(slope: number, intercept: number, outFilter?: FilterMatrix): FilterMatrix; | ||
|
||
/** | ||
* A contrast filter | ||
* See css/svg equivalent for parameters and a specification | ||
* https://www.w3.org/TR/filter-effects-1/#contrastEquivalent | ||
* https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-linear | ||
* @param contrast | ||
* @param outFilter Optional output, a new filter is created if not specified | ||
*/ | ||
export function getContrastFilter(contrast: number, outFilter?: FilterMatrix): FilterMatrix; | ||
|
||
/** | ||
* A saturate filter | ||
* See css/svg equivalent for parameters and a specification | ||
* https://www.w3.org/TR/filter-effects-1/#saturateEquivalent | ||
* https://www.w3.org/TR/filter-effects-1/#ref-for-attr-valuedef-type-saturate | ||
* @param saturate | ||
* @param outFilter Optional output, a new filter is created if not specified | ||
*/ | ||
export function getSaturateFilter(saturate: number, outFilter?: FilterMatrix): FilterMatrix; | ||
|
||
/** | ||
* A brightness filter | ||
* See css/svg equivalent for parameters and a specification | ||
* https://www.w3.org/TR/filter-effects-1/#brightnessEquivalent | ||
* https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-linear | ||
* @param brightness | ||
* @param outFilter Optional output, a new filter is created if not specified | ||
*/ | ||
export function getBrightnessFilter(brightness: number, outFilter?: FilterMatrix): FilterMatrix; | ||
|
||
/** | ||
* An invert filter | ||
* See css/svg equivalent for parameters and a specification | ||
* https://www.w3.org/TR/filter-effects-1/#invertEquivalent | ||
* https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-table | ||
* @param invert | ||
* @param outFilter Optional output, a new filter is created if not specified | ||
*/ | ||
export function getInvertFilter(invert: number, outFilter?: FilterMatrix): FilterMatrix; |
91 changes: 91 additions & 0 deletions
91
Sources/Rendering/Core/ColorTransferFunction/CssFilters.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/** | ||
* A helper file to transform RGBA points using CSS filters equivalent | ||
* The equivalents of CSS filters using SVG filters can be found here: | ||
* https://www.w3.org/TR/filter-effects-1/#ShorthandEquivalents | ||
* For each SVG filter, you can look for the maths behind it on the same page: | ||
* https://www.w3.org/TR/filter-effects-1/#FilterPrimitivesOverview | ||
* | ||
* For example, the saturate filter equivalent is here: | ||
* https://www.w3.org/TR/filter-effects-1/#saturateEquivalent | ||
* And the maths behind the feColorMatrix of type saturate is here: | ||
* https://www.w3.org/TR/filter-effects-1/#ref-for-attr-valuedef-type-saturate | ||
* | ||
* The transforms are done using matrices of size 5 by 5. They are row major | ||
* as in vtkMath. The vectors representing the RGBA points uses | ||
* [R, G, B, A, 1] vectors, with each channel between 0 and 1. | ||
*/ | ||
|
||
import { identity, multiplyMatrix } from 'vtk.js/Sources/Common/Core/Math'; | ||
|
||
export const luminanceWeights = [0.213, 0.715, 0.072]; | ||
|
||
export function getNewFilter() { | ||
return new Array(25); | ||
} | ||
|
||
export function getIdentityFilter(outFilter = getNewFilter()) { | ||
return identity(5, outFilter); | ||
} | ||
|
||
export function combineFilters( | ||
baseFilter, | ||
newFilter, | ||
outFilter = getNewFilter() | ||
) { | ||
multiplyMatrix(newFilter, baseFilter, 5, 5, 5, 5, outFilter); | ||
return outFilter; | ||
} | ||
|
||
export function applyFilter(filter, r, g, b, a = 1) { | ||
const vec = [r, g, b, a, 1]; | ||
multiplyMatrix(filter, vec, 5, 5, 5, 1, vec); | ||
return vec.slice(0, 4); | ||
} | ||
|
||
export function getLinearFilter(slope, intercept, outFilter = getNewFilter()) { | ||
getIdentityFilter(outFilter); | ||
for (let row = 0; row < 3; ++row) { | ||
outFilter[row * 5 + row] = slope; | ||
outFilter[row * 5 + 4] = intercept; | ||
} | ||
return outFilter; | ||
} | ||
|
||
// https://www.w3.org/TR/filter-effects-1/#contrastEquivalent | ||
// https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-linear | ||
export function getContrastFilter(contrast, outFilter = getNewFilter()) { | ||
const slope = contrast; | ||
const intercept = -(0.5 * contrast) + 0.5; | ||
return getLinearFilter(slope, intercept, outFilter); | ||
} | ||
|
||
// https://www.w3.org/TR/filter-effects-1/#saturateEquivalent | ||
// https://www.w3.org/TR/filter-effects-1/#ref-for-attr-valuedef-type-saturate | ||
export function getSaturateFilter(saturate, outFilter = getNewFilter()) { | ||
getIdentityFilter(outFilter); | ||
for (let col = 0; col < 3; ++col) { | ||
const columnLuminance = luminanceWeights[col]; | ||
const diagonalValue = columnLuminance + (1 - columnLuminance) * saturate; | ||
const nonDiagonalValue = columnLuminance - columnLuminance * saturate; | ||
for (let row = 0; row < 3; ++row) { | ||
outFilter[row * 5 + col] = row === col ? diagonalValue : nonDiagonalValue; | ||
} | ||
} | ||
return outFilter; | ||
} | ||
|
||
// https://www.w3.org/TR/filter-effects-1/#brightnessEquivalent | ||
// https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-linear | ||
export function getBrightnessFilter(brightness, outFilter = getNewFilter()) { | ||
const slope = brightness; | ||
const intercept = 0; | ||
return getLinearFilter(slope, intercept, outFilter); | ||
} | ||
|
||
// https://www.w3.org/TR/filter-effects-1/#invertEquivalent | ||
// https://www.w3.org/TR/filter-effects-1/#attr-valuedef-type-table | ||
export function getInvertFilter(invert, outFilter = getNewFilter()) { | ||
const slope = 1 - 2 * invert; | ||
const intercept = invert; | ||
return getLinearFilter(slope, intercept, outFilter); | ||
} |