From 5f1d4d39a99962c67db87285f858b625e3381c2c Mon Sep 17 00:00:00 2001 From: Prindl Date: Mon, 25 Feb 2019 02:25:15 +0100 Subject: [PATCH 1/3] Added filter support. Added CYMK, HSL, HSV colors. --- src/Color.js | 417 +++++++++++++++++++ src/Filter.js | 133 ++++++ src/NodeContainer.js | 3 + src/Renderer.js | 6 +- src/renderer/CanvasRenderer.js | 57 ++- tests/reftests/filter/example.jpg | Bin 0 -> 50055 bytes tests/reftests/filter/filter_brightness.html | 44 ++ tests/reftests/filter/filter_contrast.html | 44 ++ tests/reftests/filter/filter_grayscale.html | 44 ++ tests/reftests/filter/filter_huerotate.html | 44 ++ tests/reftests/filter/filter_invert.html | 44 ++ tests/reftests/filter/filter_opacity.html | 44 ++ tests/reftests/filter/filter_saturate.html | 44 ++ tests/reftests/filter/filter_sepia.html | 44 ++ 14 files changed, 964 insertions(+), 4 deletions(-) create mode 100644 src/Filter.js create mode 100644 tests/reftests/filter/example.jpg create mode 100644 tests/reftests/filter/filter_brightness.html create mode 100644 tests/reftests/filter/filter_contrast.html create mode 100644 tests/reftests/filter/filter_grayscale.html create mode 100644 tests/reftests/filter/filter_huerotate.html create mode 100644 tests/reftests/filter/filter_invert.html create mode 100644 tests/reftests/filter/filter_opacity.html create mode 100644 tests/reftests/filter/filter_saturate.html create mode 100644 tests/reftests/filter/filter_sepia.html diff --git a/src/Color.js b/src/Color.js index b8b190219..214f1e2f7 100644 --- a/src/Color.js +++ b/src/Color.js @@ -70,6 +70,11 @@ export default class Color { g: number; b: number; a: number | null; + k: number; + isHSL: boolean; + isHSV: boolean; + isCMYK: boolean; + isRGB: boolean; constructor(value: string | Array) { const [r, g, b, a] = Array.isArray(value) @@ -83,6 +88,11 @@ export default class Color { this.g = g; this.b = b; this.a = a; + this.k = 0; + this.isHSL = false; + this.isHSV = false; + this.isCMYK = false; + this.isRGB = true; } isTransparent(): boolean { @@ -94,6 +104,413 @@ export default class Color { ? `rgba(${this.r},${this.g},${this.b},${this.a})` : `rgb(${this.r},${this.g},${this.b})`; } + + hsl2rgb() { + if (this.isRGB) return; + if (!this.isHSL) return; + this.r = Math.max(0, Math.min(359, this.r)); + this.g = Math.max(0, Math.min(100, this.g)); + this.b = Math.max(0, Math.min(100, this.b)); + this.g /= 100; + this.b /= 100; + var C = (1 - Math.abs(2 * this.b - 1)) * this.g; + var h = this.r / 60; + var X = C * (1 - Math.abs(h % 2 - 1)); + var l = this.b; + this.r = 0; + this.g = 0; + this.b = 0; + if (h >= 0 && h < 1) { + this.r = C; + this.g = X; + } else if (h >= 1 && h < 2) { + this.r = X; + this.g = C; + } else if (h >= 2 && h < 3) { + this.g = C; + this.b = X; + } else if (h >= 3 && h < 4) { + this.g = X; + this.b = C; + } else if (h >= 4 && h < 5) { + this.r = X; + this.b = C; + } else { + this.r = C; + this.b = X; + } + var m = l - C / 2; + this.r += m; + this.g += m; + this.b += m; + this.r = Math.round(this.r * 255.0); + this.g = Math.round(this.g * 255.0); + this.b = Math.round(this.b * 255.0); + this.isHSL = false; + this.isRGB = true; + } + + hsv2rgb() { + if (this.isRGB) return; + if (!this.isHSV) return; + this.r = Math.max(0, Math.min(359, this.r)); + this.g = Math.max(0, Math.min(100, this.g)); + this.b = Math.max(0, Math.min(100, this.b)); + this.g /= 100; + this.b /= 100; + var C = this.g * this.b; + var h = this.r / 60; + var X = C * (1 - Math.abs(h % 2 - 1)); + var v = this.b; + this.r = 0; + this.g = 0; + this.b = 0; + if (h >= 0 && h < 1) { + this.r = C; + this.g = X; + } else if (h >= 1 && h < 2) { + this.r = X; + this.g = C; + } else if (h >= 2 && h < 3) { + this.g = C; + this.b = X; + } else if (h >= 3 && h < 4) { + this.g = X; + this.b = C; + } else if (h >= 4 && h < 5) { + this.r = X; + this.b = C; + } else { + this.r = C; + this.b = X; + } + var m = v - C; + this.r += m; + this.g += m; + this.b += m; + this.r = Math.round(this.r * 255.0); + this.g = Math.round(this.g * 255.0); + this.b = Math.round(this.b * 255.0); + this.isHSV = false; + this.isRGB = true; + } + + cmyk2rgb() { + if (this.isRGB) return; + if (!this.isCMYK) return; + this.r = Math.max(0, Math.min(100, this.r)) / 100; + this.g = Math.max(0, Math.min(100, this.g)) / 100; + this.b = Math.max(0, Math.min(100, this.b)) / 100; + this.k = Math.max(0, Math.min(100, this.k)) / 100; + this.r = Math.round((1 - this.r) * (1 - this.k) * 255); + this.g = Math.round((1 - this.g) * (1 - this.k) * 255); + this.b = Math.round((1 - this.b) * (1 - this.k) * 255); + this.isCMYK = false; + this.isRGB = true; + } + + rgb2hsl() { + if (this.isHSL) return; + if (!this.isRGB) return; + this.r = Math.max(0, Math.min(255, this.r)); + this.g = Math.max(0, Math.min(255, this.g)); + this.b = Math.max(0, Math.min(255, this.b)); + this.r /= 255; + this.g /= 255; + this.b /= 255; + var h, l, s; + var M = Math.max(this.r, this.g, this.b); + var m = Math.min(this.r, this.g, this.b); + var d = M - m; + if (d == 0) h = 0; + else if (M == this.r) h = (this.g - this.b) / d % 6; + else if (M == this.g) h = (this.b - this.r) / d + 2; + else h = (this.r - this.g) / d + 4; + h *= 60; + if (h < 0) h += 360; + this.r = h; + l = (M + m) / 2; + if (d == 0) this.g = 0; + else this.g = d / (1 - Math.abs(2 * l - 1)) * 100; + this.b = l * 100; + this.isHSL = true; + this.isRGB = false; + } + + rgb2hsv() { + if (this.isHSV) return; + if (!this.isRGB) return; + this.r = Math.max(0, Math.min(255, this.r)); + this.g = Math.max(0, Math.min(255, this.g)); + this.b = Math.max(0, Math.min(255, this.b)); + this.r /= 255; + this.g /= 255; + this.b /= 255; + var M = Math.max(this.r, this.g, this.b); + var m = Math.min(this.r, this.g, this.b); + var C = M - m; + var h, s; + if (C == 0) h = 0; + else if (M == this.r) h = (this.g - this.b) / C % 6; + else if (M == this.g) h = (this.b - this.r) / C + 2; + else h = (this.r - this.g) / C + 4; + h *= 60; + if (h < 0) h += 360; + this.r = h; + //var v = M; + if (M == 0) this.g = 0; + else this.g = C / M * 100; + this.b = M * 100; + this.isHSV = true; + this.isRGB = false; + } + + rgb2cmyk() { + if (this.isCMYK) return; + if (!this.isRGB) return; + this.r = Math.max(0, Math.min(255, this.r)); + this.g = Math.max(0, Math.min(255, this.g)); + this.b = Math.max(0, Math.min(255, this.b)); + this.r /= 255; + this.g /= 255; + this.b /= 255; + this.k = 1 - Math.max(this.r, this.g, this.b); + if (this.k == 1) { + this.r = 0; + this.g = 0; + this.b = 0; + } else { + this.r = Math.round((1 - this.r - this.k) / (1 - this.k) * 100); + this.g = Math.round((1 - this.g - this.k) / (1 - this.k) * 100); + this.b = Math.round((1 - this.b - this.k) / (1 - this.k) * 100); + } + this.k = Math.round(this.k * 100); + this.isCMYK = true; + this.isRGB = false; + } + + adjustBrightness(value: number) { + if (value < 0) value = 0; + if (this.isCMYK) { + this.cmyk2rgb(); + this.rgb2hsl(); + this.b *= value; + this.hsl2rgb(); + this.rgb2cmyk(); + } else if (this.isRGB) { + this.rgb2hsl(); + this.b *= value; + this.hsl2rgb(); + } else if (this.isHSV) { + //this.hsv2rgb(); + //this.rgb2hsl(); + this.b *= value; + //this.hsl2rgb(); + //this.rgb2hsv(); + } else if (this.isHSL) this.b *= value; + } + + brightnessRGB(value: number) { + this.r = Math.max(0, Math.min(255, this.r * value)); + this.g = Math.max(0, Math.min(255, this.g * value)); + this.b = Math.max(0, Math.min(255, this.b * value)); + } + + adjustBrightnessRGB(value: number) { + if (value < 0) value = 0; + if (this.isCMYK) { + this.cmyk2rgb(); + this.brightnessRGB(value); + this.rgb2cmyk(); + } else if (this.isHSL) { + this.hsl2rgb(); + this.brightnessRGB(value); + this.rgb2hsl(); + } else if (this.isHSV) { + this.hsv2rgb(); + this.brightnessRGB(value); + this.rgb2hsv(); + } else if (this.isRGB) { + this.brightnessRGB(value); + } + } + + contrastRGB(value: number) { + this.r = Math.max(0, Math.min(255, value * (this.r - 128) + 128)); + this.g = Math.max(0, Math.min(255, value * (this.g - 128) + 128)); + this.b = Math.max(0, Math.min(255, value * (this.b - 128) + 128)); + } + + adjustContrast(value: number) { + if (value < 0) value = 0; + else if (value > 1) value = 1; + if (this.isCMYK) { + this.cmyk2rgb(); + this.contrastRGB(value); + this.rgb2cmyk(); + } else if (this.isHSL) { + this.hsl2rgb(); + this.contrastRGB(value); + this.rgb2hsl(); + } else if (this.isHSV) { + this.hsv2rgb(); + this.contrastRGB(value); + this.rgb2hsv(); + } else if (this.isRGB) { + this.contrastRGB(value); + } + } + + grayscaleRGB(value: number, mode: ?string) { + var gray = 0; + //different grayscale algorithms + switch (mode) { + case 'average': + gray = (this.r + this.g + this.b) / 3; + break; + case 'luma:BT601': + gray = this.r * 0.299 + this.g * 0.587 + this.b * 0.114; + break; + case 'desaturation': + gray = (Math.max(this.r, this.g, this.b) + Math.max(this.r, this.g, this.b)) / 2; + break; + case 'decompsition:max': + gray = Math.max(this.r, this.g, this.b); + break; + case 'decompsition:min': + gray = Math.min(this.r, this.g, this.b); + break; + case 'luma:BT709': + default: + gray = this.r * 0.2126 + this.g * 0.7152 + this.b * 0.0722; + break; + } + this.r = value * (gray - this.r) + this.r; + this.g = value * (gray - this.g) + this.g; + this.b = value * (gray - this.b) + this.b; + } + + grayscale(value: number, mode: ?string) { + if (this.isCMYK) { + this.cmyk2rgb(); + this.grayscaleRGB(value, mode); + this.rgb2cmyk(); + } else if (this.isHSL) { + this.hsl2rgb(); + this.grayscaleRGB(value, mode); + this.rgb2hsl(); + } else if (this.isHSV) { + this.hsv2rgb(); + this.grayscaleRGB(value, mode); + this.rgb2hsv(); + } else if (this.isRGB) { + this.grayscaleRGB(value, mode); + } + } + + adjustHue(value: number) { + while (value < 0) value += 360; + while (value > 360) value -= 360; + if (this.isCMYK) { + this.cmyk2rgb(); + this.rgb2hsl(); + this.r += value; + if (this.r < 0) this.r += 360; + if (this.r > 359) this.r -= 360; + this.hsl2rgb(); + this.rgb2cmyk(); + } else if (this.isRGB) { + this.rgb2hsl(); + this.r += value; + if (this.r < 0) this.r += 360; + if (this.r > 359) this.r -= 360; + this.hsl2rgb(); + } else if (this.isHSV) { + this.r += value; + if (this.r < 0) this.r += 360; + if (this.r > 359) this.r -= 360; + } else if (this.isHSL) { + this.r += value; + if (this.r < 0) this.r += 360; + if (this.r > 359) this.r -= 360; + } + } + + invert(value: number) { + if (this.isRGB) { + this.r = value * (255 - 2 * this.r) + this.r; + this.g = value * (255 - 2 * this.g) + this.g; + this.b = value * (255 - 2 * this.b) + this.b; + } else if (this.isHSL || this.isHSV) { + this.r = value * (360 - 2 * this.r) + this.r; + this.g = value * (100 - 2 * this.g) + this.g; + this.b = value * (100 - 2 * this.b) + this.b; + } else if (this.isCMYK) { + this.r = value * (255 - 2 * this.r) + this.r; + this.g = value * (255 - 2 * this.g) + this.g; + this.b = value * (255 - 2 * this.b) + this.b; + //this.k = 1 - this.k; + } + } + + adjustSaturation(value: number) { + while (value < 0) value = 0; + if (this.isCMYK) { + this.cmyk2rgb(); + this.rgb2hsl(); + this.g *= value; + if (this.g > 100) this.g = 100; + this.hsl2rgb(); + this.rgb2cmyk(); + } else if (this.isHSL) { + this.g *= value; + if (this.g > 100) this.g = 100; + } else if (this.isHSV) { + this.g *= value; + if (this.g > 100) this.g = 100; + } else { + this.rgb2hsl(); + this.g *= value; + if (this.g > 100) this.g = 100; + this.hsl2rgb(); + } + } + + sepiaRGB(value: number) { + this.r = + value * Math.min(255, this.r * 0.393 + this.g * 0.769 + this.b * 0.189 - this.r) + + this.r; + this.g = + value * Math.min(255, this.r * 0.349 + this.g * 0.686 + this.b * 0.168 - this.g) + + this.g; + this.b = + value * Math.min(255, this.r * 0.272 + this.g * 0.534 + this.b * 0.131 - this.b) + + this.b; + } + + adjustSepia(value: number) { + if (value < 0) value = 0; + else if (value > 1) value = 1; + if (this.isRGB) { + this.sepiaRGB(value); + } else if (this.isCMYK) { + this.cmyk2rgb(); + this.sepiaRGB(value); + this.rgb2cmyk(); + } else if (this.isHSL) { + this.hsl2rgb(); + this.sepiaRGB(value); + this.rgb2hsl(); + } else if (this.isHSV) { + this.hsv2rgb(); + this.sepiaRGB(value); + this.rgb2hsv(); + } + } + + static create(s): Color { + return new Color(s); + } } const NAMED_COLORS = { diff --git a/src/Filter.js b/src/Filter.js new file mode 100644 index 000000000..a2c4091a9 --- /dev/null +++ b/src/Filter.js @@ -0,0 +1,133 @@ +/* @flow */ +'use strict'; + +export const FILTER_TYPE = { + UNDEFINED: 'none', + BRIGHTNESS: 'brightness', + CONTRAST: 'contrast', + GRAYSCALE: 'grayscale', + HUEROTATE: 'hue-rotate', + INVERT: 'invert', + OPACITY: 'opacity', + SATURATION: 'saturation', + SEPIA: 'sepia' +}; + +export default class Filter { + filterTypes: Array; + values: Array; + + constructor(value: string) { + var filters = value.split(' '); + this.filterTypes = filters.map(f => { + return f.slice(0, f.indexOf('(')); + }); + this.values = filters.map(f => { + var v = f.slice(f.indexOf('(') + 1, f.indexOf(')')); + + if (v.slice(-1) == '%') { + //turn % into 0 - 1 values + v = v.slice(0, -1); + v = Number(v); + if (v > 1) v /= 100; + } else if (v.slice(-3) == 'deg') { + //turn deg into 0 - 360, for hue-rotate + v = v.slice(0, -3); + v = Number(v); + if (v < 0) v += 360; + if (v > 360) v -= 360; + } + + return Number(v); + }); + } + + isDefined() { + if (this.filterTypes[0] == FILTER_TYPE.UNDEFINED) return false; + return true; + } + + getFilterValue(fType: string) { + for (var i = 0; i < this.filterTypes.length; i++) + if (this.filterTypes[i] == fType) return this.values[i]; + return 1; + } + hasFilterValue(fType: string) { + for (var i = 0; i < this.filterTypes.length; i++) + if (this.filterTypes[i] == fType) return true; + return false; + } + + getGrayscale() { + return this.getFilterValue(FILTER_TYPE.GRAYSCALE); + } + + getBrightness() { + return this.getFilterValue(FILTER_TYPE.BRIGHTNESS); + } + + getOpacity() { + return this.getFilterValue(FILTER_TYPE.OPACITY); + } + + getSepia() { + return this.getFilterValue(FILTER_TYPE.SEPIA); + } + + getInvert() { + return this.getFilterValue(FILTER_TYPE.INVERT); + } + + getContrast() { + return this.getFilterValue(FILTER_TYPE.CONTRAST); + } + + getSaturation() { + return this.getFilterValue(FILTER_TYPE.SATURATION); + } + + getHueRotate() { + return this.getFilterValue(FILTER_TYPE.HUEROTATE); + } + + hasGrayscale() { + return this.hasFilterValue(FILTER_TYPE.GRAYSCALE); + } + + hasBrightness() { + return this.hasFilterValue(FILTER_TYPE.BRIGHTNESS); + } + + hasOpacity() { + return this.hasFilterValue(FILTER_TYPE.OPACITY); + } + + hasSepia() { + return this.hasFilterValue(FILTER_TYPE.SEPIA); + } + + hasInvert() { + return this.hasFilterValue(FILTER_TYPE.INVERT); + } + + hasContrast() { + return this.hasFilterValue(FILTER_TYPE.CONTRAST); + } + + hasSaturation() { + return this.hasFilterValue(FILTER_TYPE.SATURATION); + } + + hasHueRotate() { + return this.hasFilterValue(FILTER_TYPE.HUEROTATE); + } + + static create(s): Filter { + return new Filter(s); + } +} + +export const parseFilter = (filterValue: string): Filter => { + if (filterValue == 'none') return Filter.create(FILTER_TYPE.UNDEFINED); + return Filter.create(filterValue); +}; diff --git a/src/NodeContainer.js b/src/NodeContainer.js index f233a38cb..15697e1e7 100644 --- a/src/NodeContainer.js +++ b/src/NodeContainer.js @@ -34,6 +34,7 @@ import {parseBackground} from './parsing/background'; import {parseBorder} from './parsing/border'; import {parseBorderRadius} from './parsing/borderRadius'; import {parseDisplay, DISPLAY} from './parsing/display'; +import Filter, {parseFilter} from './Filter'; import {parseCSSFloat, FLOAT} from './parsing/float'; import {parseFont} from './parsing/font'; import {parseLetterSpacing} from './parsing/letterSpacing'; @@ -68,6 +69,7 @@ type StyleDeclaration = { borderRadius: Array, color: Color, display: DisplayBit, + filter: Filter, float: Float, font: Font, letterSpacing: number, @@ -139,6 +141,7 @@ export default class NodeContainer { : parseBorderRadius(style), color: IS_INPUT ? INPUT_COLOR : new Color(style.color), display: display, + filter: parseFilter(style.filter || style.webkitFilter), float: parseCSSFloat(style.float), font: parseFont(style), letterSpacing: parseLetterSpacing(style.letterSpacing), diff --git a/src/Renderer.js b/src/Renderer.js index fee635ac3..1e988caed 100644 --- a/src/Renderer.js +++ b/src/Renderer.js @@ -2,6 +2,7 @@ 'use strict'; import type Color from './Color'; +import type Filter from './Filter'; import type {Path} from './drawing/Path'; import type Size from './drawing/Size'; import type Logger from './Logger'; @@ -50,7 +51,7 @@ export type RenderOptions = { export interface RenderTarget { clip(clipPaths: Array, callback: () => void): void, - drawImage(image: ImageElement, source: Bounds, destination: Bounds): void, + drawImage(image: ImageElement, source: Bounds, destination: Bounds, filter: Filter): void, drawShape(path: Path, color: Color): void, @@ -145,7 +146,8 @@ export default class Renderer { this.target.drawImage( image, new Bounds(0, 0, width, height), - contentBox + contentBox, + container.style.filter ); }); } diff --git a/src/renderer/CanvasRenderer.js b/src/renderer/CanvasRenderer.js index 3a51bc784..4a36256df 100644 --- a/src/renderer/CanvasRenderer.js +++ b/src/renderer/CanvasRenderer.js @@ -2,9 +2,10 @@ 'use strict'; import type {RenderTarget, RenderOptions} from '../Renderer'; -import type Color from '../Color'; +import Color from '../Color'; import type {Path} from '../drawing/Path'; import type Size from '../drawing/Size'; +import type Filter from '../Filter'; import type {Font} from '../parsing/font'; import type {TextDecoration} from '../parsing/textDecoration'; @@ -72,7 +73,7 @@ export default class CanvasRenderer implements RenderTarget { } } - drawImage(image: ImageElement, source: Bounds, destination: Bounds) { + drawImage(image: ImageElement, source: Bounds, destination: Bounds, filter: Filter) { this.ctx.drawImage( image, source.left, @@ -84,6 +85,58 @@ export default class CanvasRenderer implements RenderTarget { destination.width, destination.height ); + if (typeof filter !== 'undefined') { + // Redraw image with filter applied, NOTE: this also applies the filter if the imag has rounded corners? + // This function cannot be called if the image is not from the same domain. You'll get security error if you do. + var imageData = this.ctx.getImageData( + destination.left, + destination.top, + destination.width, + destination.height + ); + // This loop gets every pixels on the image and applies each filter that is supported + for (var _j = 0; _j < imageData.height; _j++) { + for (var _i = 0; _i < imageData.width; _i++) { + var index = _j * 4 * imageData.width + _i * 4; + var red = imageData.data[index]; + var green = imageData.data[index + 1]; + var blue = imageData.data[index + 2]; + var alpha = imageData.data[index + 3]; + var c = Color.create([red, green, blue, alpha]); + + if (filter.hasOpacity()) { + alpha = filter.getOpacity() * 255; + } + if (filter.hasSepia()) { + c.adjustSepia(filter.getSepia()); + } + if (filter.hasGrayscale()) { + c.grayscale(filter.getGrayscale(), 'luma:BT709'); + } + if (filter.hasBrightness()) { + c.adjustBrightnessRGB(filter.getBrightness()); + } + if (filter.hasHueRotate()) { + c.adjustHue(filter.getHueRotate()); + } + if (filter.hasSaturation()) { + c.adjustSaturation(filter.getSaturation()); + } + if (filter.hasInvert()) { + c.invert(filter.getInvert()); + } + if (filter.hasContrast()) { + c.adjustContrast(filter.getContrast()); + } + + imageData.data[index] = c.r; + imageData.data[index + 1] = c.g; + imageData.data[index + 2] = c.b; + imageData.data[index + 3] = alpha; + } + } + this.ctx.putImageData(imageData, destination.left, destination.top); + } } drawShape(path: Path, color: Color) { diff --git a/tests/reftests/filter/example.jpg b/tests/reftests/filter/example.jpg new file mode 100644 index 0000000000000000000000000000000000000000..ff9b583cd56992a51314ca5b78a63411a3c1afa0 GIT binary patch literal 50055 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�oc-R7Dj2fW@jW& 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

!YXVijAd|;Bgwar%UP~Ri`iYX5f;c zfdBvlCsbFgVid&@+e_de`UNwqFXo9wIk!J=AM|}va9;@Uj@kV5YMJKJz??ANvmAaf zvN>iVcIWAlJJ?un8(PPD1i&*drdQzJhVg;;?R%9t;w5f7wip$nzjeUDl%BWUeSg#} z0~i5<5r*{*3^4oFSK~HqMEsO#l>Y!Vkxxm{f#zH^$GCh&rj8hII-V~0k{CX68G*%U z?8K6ZIDWj4bLY>>YG`4G2fT6?e+X??qyE2MyLxaO+%kpilO{voK?Gzp(94Dcs$BKO ziN8r=Dic=Tu}HT+D_W|!2VwLOP}6hah8Td4zZaomQPN~6oQ(efT}ry7{6IkXFc}3* zFe7*|jcL`;TQ-Ec9gjaHbA!0s)4e$Fef=(7>gtYiFbkdD^{e7?iaVZf=QNrXMdjv; zhxm#|=kh=+PiEFU*eKn0mAX1eLI4vqX!BOT&a*F0YT|J-1K|uYB+TD(^pRD-dGHcTZ`4}blzzL%=C3tmk27PxoW5NMf=ho;a&EJRnv?U_ z-ZfZri*8+AbZtW;Ea%>#!mFyUI4bY%Cpi9=9bQ>Ho&^lB2!eUnU6 zM=|SmDE|PZt;*oad1^|Ptz^wgNHCVOd+)tWNCAIP*4*2noxBp2Xg@>)>@6EHr9XXC zn|E>jSJjKqyFAjqT&I@ezFc`{%CF=+&3Rh-sqcv8kjtXJ~j zqZMIRE14vGZO|G{k)+5zhBOH8&o!7GLxJvj^>M|RHhmq)X{I_8ome)a&_1T*sl;Sk zbWKuTQMxztk3i>YBQl_m?;oM_JM#`58Ag9f=c0$Bql_m(xMEWWU!*(f(H4ssn)s`O?W z=aXMcRk1#np-nZDr$57kXB1njZW?}+S{@c9nB%3WeS87Vp0Y@C^98_oK_0QLy1Mh7 z%Ae<9`f@a9|HJ?>5dZ=L0R#d80s{yF0{{R3000335g`K*5-}n{Q4=5pVR15nk)g4{ z(eM;PBQrz)+5iXv0|5g+01%mhSgftR@9SzSYTb5nMH$+LpCm8XF=cNUI$iJVv{&Ck zeU-L%#?JC*>{E-2C8MYExEtnEw?`5@iMh>dUsQ9WUEXmoDnLRgfbT#9x{7B7mj#k*Q zwq(xeQe0Ur4MF`C^2YM^^d*)#He{sCv6a3!i)ua!+R6SNR-Qf$FT`R!qRj1OeVT45 z%yM>7=yH5wDEO_ic(Ges;9c)#OEXA}U3SMTGP@I0(^5senK0;5ZZEUe$tz>l zo%&rAP}`wFSpAtYDrR?~Nm+e;iYnOVnu%p?@=HQ$Q6sGtIQueToHd+?xbm_RR~Kjh z05$u}Ui?+FBW6sVFJ{UY1NL$6vAmM>B_GVOr)#t8 zXmZqfjvx6IIB5R>AMiW1-_G?Ej2!;}LX~~FFvVi^wd%oszt~bm8Kh?iq4g0gBRDS% zXmWp%{{U1ZB&iSH+|!fjYHBhS6pkv{Z)@8Yc^GAH$5noY3h4BTF9KhoFM)d(Y>M_q ztV^={66^=O(&G7-$?8QxE0Y$2{)Bs zCi03-#;0E=$@ONUir2`%Po(M{;&Q1r7HLmmQ{)gNj%uKH5HFrQy;R5 zp6bkrIvQ$7!e$f^;&yo7*;ze}x+qLaR$DxTq$I@r5&g=S7yi-3DIqBNGCFWi{>;Kc z`l7A)yENdr$^BB^hJqKkLBqm#0kJMkPH zdt&C4OtE=4?Z4z@N7;XZdOq7r`2PTkBN#0x^oFRinaT*WixpE8o%3l52_)?=YIuJQEp%mNvy7N>%BZFxlv6^vLkC+bMFR!sQVU`*~=(Wmm|W8g8Qtg6r#7NN<&ey-#6&a)_60{jF#x9ji_gf zY?D@=2}3bfI$XOgoFH@5P(@>JlEuFkna$jK8Xb#^OpGL>5ozeF_qH~zHlKikDvNb5AyFRwHzK&R3eU4EpRThz! zT(-rO>7NIPqZ&oKCY3@T#BN;m9lzvYv)|oEaodw6DJHrtR8|fuhh?({3e-n}DKjmW mipR-rj;u^=@nVX|k?8b#-oDozMYZI<#RW)h*;_qHQUBT99b}dO literal 0 HcmV?d00001 diff --git a/tests/reftests/filter/filter_brightness.html b/tests/reftests/filter/filter_brightness.html new file mode 100644 index 000000000..fe65f1624 --- /dev/null +++ b/tests/reftests/filter/filter_brightness.html @@ -0,0 +1,44 @@ + + + + Filter:brightness tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_contrast.html b/tests/reftests/filter/filter_contrast.html new file mode 100644 index 000000000..679edd577 --- /dev/null +++ b/tests/reftests/filter/filter_contrast.html @@ -0,0 +1,44 @@ + + + + Filter:contrast tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_grayscale.html b/tests/reftests/filter/filter_grayscale.html new file mode 100644 index 000000000..84acde44f --- /dev/null +++ b/tests/reftests/filter/filter_grayscale.html @@ -0,0 +1,44 @@ + + + + Filter:grayscale tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_huerotate.html b/tests/reftests/filter/filter_huerotate.html new file mode 100644 index 000000000..ab40caff0 --- /dev/null +++ b/tests/reftests/filter/filter_huerotate.html @@ -0,0 +1,44 @@ + + + + Filter:hue-rotate tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_invert.html b/tests/reftests/filter/filter_invert.html new file mode 100644 index 000000000..cc17fd6f5 --- /dev/null +++ b/tests/reftests/filter/filter_invert.html @@ -0,0 +1,44 @@ + + + + Filter:invert tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_opacity.html b/tests/reftests/filter/filter_opacity.html new file mode 100644 index 000000000..fe3d44e76 --- /dev/null +++ b/tests/reftests/filter/filter_opacity.html @@ -0,0 +1,44 @@ + + + + Filter:opacity tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_saturate.html b/tests/reftests/filter/filter_saturate.html new file mode 100644 index 000000000..90d066e2f --- /dev/null +++ b/tests/reftests/filter/filter_saturate.html @@ -0,0 +1,44 @@ + + + + Filter:saturate tests + + + + + + + + + + + + diff --git a/tests/reftests/filter/filter_sepia.html b/tests/reftests/filter/filter_sepia.html new file mode 100644 index 000000000..4e7a928ef --- /dev/null +++ b/tests/reftests/filter/filter_sepia.html @@ -0,0 +1,44 @@ + + + + Filter:sepia tests + + + + + + + + + + + + From aa6d123b355133a00587477f9c2be31e75d3b673 Mon Sep 17 00:00:00 2001 From: Prindl Date: Tue, 26 Feb 2019 14:53:02 +0100 Subject: [PATCH 2/3] Fixed a bug with opacity. --- src/Color.js | 19 +++++++++++++++++++ src/renderer/CanvasRenderer.js | 13 +++++++++---- 2 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/Color.js b/src/Color.js index 214f1e2f7..43aa4570a 100644 --- a/src/Color.js +++ b/src/Color.js @@ -289,6 +289,25 @@ export default class Color { this.isRGB = false; } + blend(color: Color, opacity){ + if (opacity > 1) opacity /= 255; + this.r = opacity * (this.r - color.r) + color.r; + this.g = opacity * (this.g - color.g) + color.g; + this.b = opacity * (this.b - color.b) + color.b; + this.a = 255; + } + + clip(){ + if(this.r > 255) this.r = 255; + if(this.g > 255) this.g = 255; + if(this.b > 255) this.b = 255; + if(this.a > 255) this.a = 255; + if(this.r < 0) this.r = 0; + if(this.g < 0) this.g = 0; + if(this.b < 0) this.b = 0; + if(this.a < 0) this.a = 0; + } + adjustBrightness(value: number) { if (value < 0) value = 0; if (this.isCMYK) { diff --git a/src/renderer/CanvasRenderer.js b/src/renderer/CanvasRenderer.js index 4a36256df..8382bb8fd 100644 --- a/src/renderer/CanvasRenderer.js +++ b/src/renderer/CanvasRenderer.js @@ -104,9 +104,6 @@ export default class CanvasRenderer implements RenderTarget { var alpha = imageData.data[index + 3]; var c = Color.create([red, green, blue, alpha]); - if (filter.hasOpacity()) { - alpha = filter.getOpacity() * 255; - } if (filter.hasSepia()) { c.adjustSepia(filter.getSepia()); } @@ -128,11 +125,19 @@ export default class CanvasRenderer implements RenderTarget { if (filter.hasContrast()) { c.adjustContrast(filter.getContrast()); } + if (filter.hasOpacity()) { + //opacity filter is applied last, because it blends with the BG and sets opacity to 1 + c.a = filter.getOpacity(); + if (typeof this.options.backgroundColor !== "undefined") { + c.blend(this.options.backgroundColor, c.a); + } + } + imageData.data[index] = c.r; imageData.data[index + 1] = c.g; imageData.data[index + 2] = c.b; - imageData.data[index + 3] = alpha; + imageData.data[index + 3] = c.a; } } this.ctx.putImageData(imageData, destination.left, destination.top); From 362744c64cc1d19118cee44b35668dded12f42f3 Mon Sep 17 00:00:00 2001 From: Prindl Date: Sun, 2 Feb 2020 09:34:36 +0100 Subject: [PATCH 3/3] Removed CYMK color space. It is not necessary. --- src/Color.js | 137 +++++++-------------------------------------------- 1 file changed, 18 insertions(+), 119 deletions(-) diff --git a/src/Color.js b/src/Color.js index 43aa4570a..81763f744 100644 --- a/src/Color.js +++ b/src/Color.js @@ -70,10 +70,8 @@ export default class Color { g: number; b: number; a: number | null; - k: number; isHSL: boolean; isHSV: boolean; - isCMYK: boolean; isRGB: boolean; constructor(value: string | Array) { @@ -88,10 +86,8 @@ export default class Color { this.g = g; this.b = b; this.a = a; - this.k = 0; this.isHSL = false; this.isHSV = false; - this.isCMYK = false; this.isRGB = true; } @@ -109,10 +105,8 @@ export default class Color { if (this.isRGB) return; if (!this.isHSL) return; this.r = Math.max(0, Math.min(359, this.r)); - this.g = Math.max(0, Math.min(100, this.g)); - this.b = Math.max(0, Math.min(100, this.b)); - this.g /= 100; - this.b /= 100; + this.g = Math.max(0, Math.min(100, this.g)) / 100; + this.b = Math.max(0, Math.min(100, this.b)) / 100; var C = (1 - Math.abs(2 * this.b - 1)) * this.g; var h = this.r / 60; var X = C * (1 - Math.abs(h % 2 - 1)); @@ -154,10 +148,8 @@ export default class Color { if (this.isRGB) return; if (!this.isHSV) return; this.r = Math.max(0, Math.min(359, this.r)); - this.g = Math.max(0, Math.min(100, this.g)); - this.b = Math.max(0, Math.min(100, this.b)); - this.g /= 100; - this.b /= 100; + this.g = Math.max(0, Math.min(100, this.g)) / 100; + this.b = Math.max(0, Math.min(100, this.b)) / 100; var C = this.g * this.b; var h = this.r / 60; var X = C * (1 - Math.abs(h % 2 - 1)); @@ -195,29 +187,12 @@ export default class Color { this.isRGB = true; } - cmyk2rgb() { - if (this.isRGB) return; - if (!this.isCMYK) return; - this.r = Math.max(0, Math.min(100, this.r)) / 100; - this.g = Math.max(0, Math.min(100, this.g)) / 100; - this.b = Math.max(0, Math.min(100, this.b)) / 100; - this.k = Math.max(0, Math.min(100, this.k)) / 100; - this.r = Math.round((1 - this.r) * (1 - this.k) * 255); - this.g = Math.round((1 - this.g) * (1 - this.k) * 255); - this.b = Math.round((1 - this.b) * (1 - this.k) * 255); - this.isCMYK = false; - this.isRGB = true; - } - rgb2hsl() { if (this.isHSL) return; if (!this.isRGB) return; - this.r = Math.max(0, Math.min(255, this.r)); - this.g = Math.max(0, Math.min(255, this.g)); - this.b = Math.max(0, Math.min(255, this.b)); - this.r /= 255; - this.g /= 255; - this.b /= 255; + this.r = Math.max(0, Math.min(255, this.r)) / 255; + this.g = Math.max(0, Math.min(255, this.g)) / 255; + this.b = Math.max(0, Math.min(255, this.b)) / 255; var h, l, s; var M = Math.max(this.r, this.g, this.b); var m = Math.min(this.r, this.g, this.b); @@ -240,12 +215,9 @@ export default class Color { rgb2hsv() { if (this.isHSV) return; if (!this.isRGB) return; - this.r = Math.max(0, Math.min(255, this.r)); - this.g = Math.max(0, Math.min(255, this.g)); - this.b = Math.max(0, Math.min(255, this.b)); - this.r /= 255; - this.g /= 255; - this.b /= 255; + this.r = Math.max(0, Math.min(255, this.r)) / 255; + this.g = Math.max(0, Math.min(255, this.g)) / 255; + this.b = Math.max(0, Math.min(255, this.b)) / 255; var M = Math.max(this.r, this.g, this.b); var m = Math.min(this.r, this.g, this.b); var C = M - m; @@ -265,30 +237,6 @@ export default class Color { this.isRGB = false; } - rgb2cmyk() { - if (this.isCMYK) return; - if (!this.isRGB) return; - this.r = Math.max(0, Math.min(255, this.r)); - this.g = Math.max(0, Math.min(255, this.g)); - this.b = Math.max(0, Math.min(255, this.b)); - this.r /= 255; - this.g /= 255; - this.b /= 255; - this.k = 1 - Math.max(this.r, this.g, this.b); - if (this.k == 1) { - this.r = 0; - this.g = 0; - this.b = 0; - } else { - this.r = Math.round((1 - this.r - this.k) / (1 - this.k) * 100); - this.g = Math.round((1 - this.g - this.k) / (1 - this.k) * 100); - this.b = Math.round((1 - this.b - this.k) / (1 - this.k) * 100); - } - this.k = Math.round(this.k * 100); - this.isCMYK = true; - this.isRGB = false; - } - blend(color: Color, opacity){ if (opacity > 1) opacity /= 255; this.r = opacity * (this.r - color.r) + color.r; @@ -310,13 +258,7 @@ export default class Color { adjustBrightness(value: number) { if (value < 0) value = 0; - if (this.isCMYK) { - this.cmyk2rgb(); - this.rgb2hsl(); - this.b *= value; - this.hsl2rgb(); - this.rgb2cmyk(); - } else if (this.isRGB) { + if (this.isRGB) { this.rgb2hsl(); this.b *= value; this.hsl2rgb(); @@ -337,11 +279,7 @@ export default class Color { adjustBrightnessRGB(value: number) { if (value < 0) value = 0; - if (this.isCMYK) { - this.cmyk2rgb(); - this.brightnessRGB(value); - this.rgb2cmyk(); - } else if (this.isHSL) { + if (this.isHSL) { this.hsl2rgb(); this.brightnessRGB(value); this.rgb2hsl(); @@ -363,11 +301,7 @@ export default class Color { adjustContrast(value: number) { if (value < 0) value = 0; else if (value > 1) value = 1; - if (this.isCMYK) { - this.cmyk2rgb(); - this.contrastRGB(value); - this.rgb2cmyk(); - } else if (this.isHSL) { + if (this.isHSL) { this.hsl2rgb(); this.contrastRGB(value); this.rgb2hsl(); @@ -410,11 +344,7 @@ export default class Color { } grayscale(value: number, mode: ?string) { - if (this.isCMYK) { - this.cmyk2rgb(); - this.grayscaleRGB(value, mode); - this.rgb2cmyk(); - } else if (this.isHSL) { + if (this.isHSL) { this.hsl2rgb(); this.grayscaleRGB(value, mode); this.rgb2hsl(); @@ -430,25 +360,13 @@ export default class Color { adjustHue(value: number) { while (value < 0) value += 360; while (value > 360) value -= 360; - if (this.isCMYK) { - this.cmyk2rgb(); - this.rgb2hsl(); - this.r += value; - if (this.r < 0) this.r += 360; - if (this.r > 359) this.r -= 360; - this.hsl2rgb(); - this.rgb2cmyk(); - } else if (this.isRGB) { + if (this.isRGB) { this.rgb2hsl(); this.r += value; if (this.r < 0) this.r += 360; if (this.r > 359) this.r -= 360; this.hsl2rgb(); - } else if (this.isHSV) { - this.r += value; - if (this.r < 0) this.r += 360; - if (this.r > 359) this.r -= 360; - } else if (this.isHSL) { + } else { this.r += value; if (this.r < 0) this.r += 360; if (this.r > 359) this.r -= 360; @@ -460,38 +378,23 @@ export default class Color { this.r = value * (255 - 2 * this.r) + this.r; this.g = value * (255 - 2 * this.g) + this.g; this.b = value * (255 - 2 * this.b) + this.b; - } else if (this.isHSL || this.isHSV) { + } else { this.r = value * (360 - 2 * this.r) + this.r; this.g = value * (100 - 2 * this.g) + this.g; this.b = value * (100 - 2 * this.b) + this.b; - } else if (this.isCMYK) { - this.r = value * (255 - 2 * this.r) + this.r; - this.g = value * (255 - 2 * this.g) + this.g; - this.b = value * (255 - 2 * this.b) + this.b; - //this.k = 1 - this.k; } } adjustSaturation(value: number) { while (value < 0) value = 0; - if (this.isCMYK) { - this.cmyk2rgb(); + if (this.isRGB) { this.rgb2hsl(); this.g *= value; if (this.g > 100) this.g = 100; this.hsl2rgb(); - this.rgb2cmyk(); - } else if (this.isHSL) { - this.g *= value; - if (this.g > 100) this.g = 100; - } else if (this.isHSV) { - this.g *= value; - if (this.g > 100) this.g = 100; } else { - this.rgb2hsl(); this.g *= value; if (this.g > 100) this.g = 100; - this.hsl2rgb(); } } @@ -512,10 +415,6 @@ export default class Color { else if (value > 1) value = 1; if (this.isRGB) { this.sepiaRGB(value); - } else if (this.isCMYK) { - this.cmyk2rgb(); - this.sepiaRGB(value); - this.rgb2cmyk(); } else if (this.isHSL) { this.hsl2rgb(); this.sepiaRGB(value);