├── .DS_Store ├── .babelrc ├── .github └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── ChangeLogs.md ├── LICENSE ├── README.md ├── addon ├── codemirror-colorpicker.css ├── codemirror-colorpicker.js ├── colorpicker │ ├── colorpicker.css │ ├── colorpicker.js │ └── colorview.js └── sample │ └── colorpicker.html ├── config ├── rollup.config.dev.js └── rollup.config.prod.js ├── dist ├── codemirror-colorpicker.css ├── codemirror-colorpicker.js └── codemirror-colorpicker.min.js ├── gl.html ├── index.html ├── package.json ├── resources └── image │ ├── colorpaletts.png │ ├── colorpicker.png │ ├── grapes.jpg │ ├── palette-type.png │ ├── scalecolors-title.png │ ├── scalecolors.png │ ├── screen-shot.png │ └── sketch-type.png ├── src ├── colorpicker │ ├── BaseBox.js │ ├── BaseColorPicker.js │ ├── BaseModule.js │ ├── BaseSlider.js │ ├── BaseStore.js │ ├── UIElement.js │ ├── VerticalSlider.js │ ├── box │ │ ├── ColorControl.js │ │ └── index.js │ ├── chromedevtool │ │ ├── ColorControl.js │ │ └── index.js │ ├── index.js │ ├── macos │ │ ├── ColorControl.js │ │ └── index.js │ ├── mini-vertical │ │ ├── ColorControl.js │ │ └── index.js │ ├── mini │ │ ├── ColorControl.js │ │ └── index.js │ ├── module │ │ ├── ColorManager.js │ │ └── ColorSetsList.js │ ├── ring │ │ ├── ColorControl.js │ │ └── index.js │ ├── ui │ │ ├── ColorInformation.js │ │ ├── ColorPalette.js │ │ ├── ColorRing.js │ │ ├── ColorSetsChooser.js │ │ ├── ColorWheel.js │ │ ├── CurrentColorSets.js │ │ ├── CurrentColorSetsContextMenu.js │ │ ├── Eyedropper.js │ │ ├── Eyedropper.scss │ │ └── control │ │ │ ├── Hue.js │ │ │ ├── Opacity.js │ │ │ ├── Value.js │ │ │ ├── VerticalHue.js │ │ │ └── VerticalOpacity.js │ ├── vscode │ │ ├── ColorControl.js │ │ └── index.js │ └── xd │ │ ├── ColorControl.js │ │ └── index.js ├── extension │ └── codemirror │ │ ├── colorview.js │ │ └── index.js ├── index.js ├── scss │ ├── colorpicker.scss │ ├── colorview.scss │ ├── component │ │ ├── button.scss │ │ ├── colorchooser.scss │ │ ├── colorsets-contextmenu.scss │ │ ├── colorsets.scss │ │ ├── control.scss │ │ ├── gradient-editor.scss │ │ ├── gradient-picker.scss │ │ ├── information.scss │ │ └── palette.scss │ ├── index.scss │ ├── mixins.scss │ └── themes │ │ ├── box.scss │ │ ├── macos.scss │ │ ├── mini-vertical.scss │ │ ├── mini.scss │ │ ├── palette.scss │ │ ├── ring.scss │ │ ├── sketch.scss │ │ ├── vscode.scss │ │ └── xd.scss └── util │ ├── Blender.js │ ├── Canvas.js │ ├── Color.js │ ├── ColorNames.js │ ├── Dom.js │ ├── Event.js │ ├── EventMachin.js │ ├── GL.js │ ├── HueColor.js │ ├── ImageFilter.js │ ├── ImageLoader.js │ ├── Kmeans.js │ ├── Matrix.js │ ├── State.js │ ├── blend │ ├── composite.js │ ├── non-separable.js │ └── separable.js │ ├── filter │ ├── StackBlur.js │ ├── functions.js │ ├── image │ │ ├── crop.js │ │ ├── flipH.js │ │ ├── flipV.js │ │ ├── histogram.js │ │ ├── index.js │ │ ├── resize.js │ │ ├── rotate.js │ │ └── rotateDegree.js │ ├── index.js │ ├── matrix │ │ ├── blur.js │ │ ├── emboss.js │ │ ├── gaussian-blur-5x.js │ │ ├── gaussian-blur.js │ │ ├── grayscale2.js │ │ ├── index.js │ │ ├── kirsch-horizontal.js │ │ ├── kirsch-vertical.js │ │ ├── laplacian-5x.js │ │ ├── laplacian.js │ │ ├── motion-blur-2.js │ │ ├── motion-blur-3.js │ │ ├── motion-blur.js │ │ ├── negative.js │ │ ├── normal.js │ │ ├── sepia2.js │ │ ├── sharpen.js │ │ ├── sobel-horizontal.js │ │ ├── sobel-vertical.js │ │ ├── stack-blur.js │ │ ├── transparency.js │ │ └── unsharp-masking.js │ ├── multi │ │ ├── index.js │ │ ├── kirsch.js │ │ ├── sobel.js │ │ └── vintage.js │ └── pixel │ │ ├── bitonal.js │ │ ├── brightness.js │ │ ├── brownie.js │ │ ├── clip.js │ │ ├── contrast.js │ │ ├── gamma.js │ │ ├── gradient.js │ │ ├── grayscale.js │ │ ├── hue.js │ │ ├── index.js │ │ ├── invert.js │ │ ├── kodachrome.js │ │ ├── matrix.js │ │ ├── noise.js │ │ ├── opacity.js │ │ ├── polaroid.js │ │ ├── saturation.js │ │ ├── sepia.js │ │ ├── shade.js │ │ ├── shift.js │ │ ├── solarize.js │ │ ├── technicolor.js │ │ ├── threshold-color.js │ │ ├── threshold.js │ │ └── tint.js │ ├── functions │ ├── formatter.js │ ├── fromCMYK.js │ ├── fromHSL.js │ ├── fromHSV.js │ ├── fromLAB.js │ ├── fromRGB.js │ ├── fromYCrCb.js │ ├── func.js │ ├── image.js │ ├── math.js │ ├── mixin.js │ ├── parser.js │ └── support.js │ ├── gl │ ├── filter │ │ ├── index.js │ │ ├── matrix │ │ │ ├── blur.js │ │ │ ├── emboss.js │ │ │ ├── gaussian-blur-5x.js │ │ │ ├── gaussian-blur.js │ │ │ ├── grayscale2.js │ │ │ ├── index.js │ │ │ ├── kirsch-horizontal.js │ │ │ ├── kirsch-vertical.js │ │ │ ├── laplacian-5x.js │ │ │ ├── laplacian.js │ │ │ ├── motion-blur-2.js │ │ │ ├── motion-blur-3.js │ │ │ ├── motion-blur.js │ │ │ ├── negative.js │ │ │ ├── normal.js │ │ │ ├── sepia2.js │ │ │ ├── sharpen.js │ │ │ ├── sobel-horizontal.js │ │ │ ├── sobel-vertical.js │ │ │ ├── transparency.js │ │ │ └── unsharp-masking.js │ │ ├── multi │ │ │ ├── index.js │ │ │ ├── kirsch.js │ │ │ ├── sobel.js │ │ │ └── vintage.js │ │ ├── pixel │ │ │ ├── bitonal.js │ │ │ ├── brightness.js │ │ │ ├── brownie.js │ │ │ ├── chaos.js │ │ │ ├── clip.js │ │ │ ├── contrast.js │ │ │ ├── gamma.js │ │ │ ├── gradient.js │ │ │ ├── grayscale.js │ │ │ ├── hue.js │ │ │ ├── index.js │ │ │ ├── invert.js │ │ │ ├── kodachrome.js │ │ │ ├── matrix.js │ │ │ ├── noise.js │ │ │ ├── opacity.js │ │ │ ├── polaroid.js │ │ │ ├── saturation.js │ │ │ ├── sepia.js │ │ │ ├── shade.js │ │ │ ├── shift.js │ │ │ ├── solarize.js │ │ │ ├── technicolor.js │ │ │ ├── threshold-color.js │ │ │ ├── threshold.js │ │ │ └── tint.js │ │ └── util.js │ ├── functions.js │ └── index.js │ └── index.js ├── stand.html └── test ├── util.Blend.spec.js ├── util.Color.spec.js ├── util.Filter.spec.js └── util.ImageFilter.spec.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/.DS_Store -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "test": { 4 | "presets" : [ ["env"] ], 5 | "plugins": [ 6 | "transform-es2015-modules-commonjs", 7 | "transform-object-rest-spread" 8 | ] 9 | }, 10 | "development" : { 11 | "presets" : [ 12 | [ "env", {"modules" : false } ] 13 | ], 14 | "plugins": [ 15 | "external-helpers", 16 | "transform-object-rest-spread" 17 | ] 18 | }, 19 | "production" : { 20 | "presets" : [ 21 | [ "env", {"modules" : false } ] 22 | ], 23 | "plugins": [ 24 | "external-helpers", 25 | "transform-object-rest-spread" 26 | ] 27 | } 28 | } 29 | 30 | } -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | 5 | --- 6 | 7 | **Describe the bug** 8 | A clear and concise description of what the bug is. 9 | 10 | **To Reproduce** 11 | Steps to reproduce the behavior: 12 | 1. Go to '...' 13 | 2. Click on '....' 14 | 3. Scroll down to '....' 15 | 4. See error 16 | 17 | **Expected behavior** 18 | A clear and concise description of what you expected to happen. 19 | 20 | **Screenshots** 21 | If applicable, add screenshots to help explain your problem. 22 | 23 | **Desktop (please complete the following information):** 24 | - OS: [e.g. iOS] 25 | - Browser [e.g. chrome, safari] 26 | - Version [e.g. 22] 27 | 28 | **Smartphone (please complete the following information):** 29 | - Device: [e.g. iPhone6] 30 | - OS: [e.g. iOS8.1] 31 | - Browser [e.g. stock browser, safari] 32 | - Version [e.g. 22] 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | **Is your feature request related to a problem? Please describe.** 8 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 9 | 10 | **Describe the solution you'd like** 11 | A clear and concise description of what you want to happen. 12 | 13 | **Describe alternatives you've considered** 14 | A clear and concise description of any alternative solutions or features you've considered. 15 | 16 | **Additional context** 17 | Add any other context or screenshots about the feature request here. 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | .DS_Store 3 | test-report/ 4 | package-lock.json -------------------------------------------------------------------------------- /ChangeLogs.md: -------------------------------------------------------------------------------- 1 | 2 | # Change Logs 3 | 4 | # 1.6.5 5 | * image filter (gray) 6 | * support lab color (RGBtoLAB, LABtoRGB) 7 | 8 | # 1.6.4 9 | * improved performance of color palette for image 10 | * support only palette style 11 | 12 | ## 1.6.3 13 | * Support Sketch Style 14 | * support color palette for image 15 | * support parsing for number color code (ex: 0xffffff -> {hex, r, g, b, a}) 16 | 17 | ## v1.6.0 18 | * support color scale 19 | 20 | ## v1.5.0 21 | * change bundler - rollup based 22 | * support color palettes 23 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 jinho park (cyberuls@gmail.com, easylogic) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config/rollup.config.dev.js: -------------------------------------------------------------------------------- 1 | import packageJSON from '../package.json' 2 | import postcss from 'rollup-plugin-postcss' 3 | import babel from 'rollup-plugin-babel'; 4 | import serve from 'rollup-plugin-serve' 5 | import livereload from 'rollup-plugin-livereload' 6 | import autoprefixer from 'autoprefixer' 7 | import glslify from 'rollup-plugin-glslify'; 8 | import peerDepsExternal from 'rollup-plugin-peer-deps-external'; 9 | 10 | // rollup.config.js 11 | export default { 12 | input: 'src/index.js', 13 | output: { 14 | file: 'addon/' + packageJSON.name + '.js', 15 | format: 'iife', 16 | globals: { 17 | "codemirror" : "window.CodeMirror" 18 | }, 19 | external: ['codemirror'] 20 | }, 21 | name: 'CodeMirrorColorPicker', 22 | plugins : [ 23 | peerDepsExternal(), 24 | serve(), 25 | livereload({watch: 'addon'}), 26 | glslify({ basedir: 'src/util/glsl/source' }), 27 | //scss({output : 'addon/' + packageJSON.name + '.css'}), 28 | postcss({ 29 | extract: 'addon/' + packageJSON.name + '.css', 30 | plugins: [ 31 | autoprefixer() 32 | ], 33 | extensions: ['.scss'] 34 | }), 35 | babel({ 36 | exclude: ['node_modules/**', 'src/util/glsl/source/**'], 37 | presets: [ 38 | [ 'es2015', { modules : false } ] 39 | ] 40 | }) 41 | ], 42 | watch: { 43 | chokidar: { 44 | // if the chokidar option is given, rollup-watch will 45 | // use it instead of fs.watch. You will need to install 46 | // chokidar separately. 47 | // 48 | // this options object is passed to chokidar. if you 49 | // don't have any options, just pass `chokidar: true` 50 | }, 51 | 52 | // include and exclude govern which files to watch. by 53 | // default, all dependencies will be watched 54 | exclude: ['node_modules/**'] 55 | } 56 | }; -------------------------------------------------------------------------------- /config/rollup.config.prod.js: -------------------------------------------------------------------------------- 1 | import packageJSON from '../package.json' 2 | import postcss from 'rollup-plugin-postcss' 3 | import babel from 'rollup-plugin-babel'; 4 | import uglify from 'rollup-plugin-uglify'; 5 | import autoprefixer from 'autoprefixer' 6 | import glslify from 'rollup-plugin-glslify'; 7 | import peerDepsExternal from 'rollup-plugin-peer-deps-external'; 8 | 9 | 10 | // rollup.config.js 11 | export default [{ 12 | input: 'src/index.js', 13 | output: { 14 | file: 'dist/' + packageJSON.name + '.min.js', 15 | format: 'iife', 16 | globals: { 17 | "codemirror" : "window.CodeMirror" 18 | }, 19 | external: ['codemirror'] 20 | }, 21 | name: 'CodeMirrorColorPicker', 22 | plugins : [ 23 | peerDepsExternal(), 24 | glslify({ basedir: 'src/util/glsl/source' }), 25 | //scss({output : 'dist/' + packageJSON.name + '.css'}), 26 | postcss({ 27 | extract: 'dist/' + packageJSON.name + '.css', 28 | plugins: [ 29 | autoprefixer() 30 | ], 31 | extensions: ['.scss'] 32 | }), 33 | babel({ 34 | exclude: ['node_modules/**', 'src/util/glsl/source/**'] 35 | }), 36 | uglify() 37 | ] 38 | }, { 39 | input: 'src/index.js', 40 | output: { 41 | file: 'dist/' + packageJSON.name + '.js', 42 | format: 'umd', 43 | globals: { 44 | "codemirror" : "CodeMirror" 45 | }, 46 | external: ['codemirror'] 47 | }, 48 | name: 'codemirror-colorpicker', 49 | plugins : [ 50 | postcss({ 51 | extract: 'dist/' + packageJSON.name + '.css', 52 | plugins: [ 53 | autoprefixer() 54 | ], 55 | extensions: ['.scss'] 56 | }), 57 | babel({ 58 | exclude: 'node_modules/**' 59 | }) 60 | ] 61 | }]; -------------------------------------------------------------------------------- /gl.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 35 | 36 | 37 | 38 |
39 | 40 |
41 | 42 | 43 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codemirror-colorpicker", 3 | "version": "1.9.80", 4 | "description": "simple colorpicker used anywhere", 5 | "main": "./dist/codemirror-colorpicker.js", 6 | "scripts": { 7 | "pub": "npm run build && npm publish", 8 | "build": "NODE_ENV=production rollup --config config/rollup.config.prod.js", 9 | "dev": "NODE_ENV=development rollup -w --config config/rollup.config.dev.js", 10 | "docs": "http-server ./docs", 11 | "test": "NODE_ENV=test jest --watch" 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/easylogic/codemirror-colorpicker.git" 16 | }, 17 | "keywords": [ 18 | "codemirror", 19 | "colorview", 20 | "colorpicker", 21 | "imagefilter", 22 | "color", 23 | "rgb", 24 | "webgl", 25 | "chromdevtool", 26 | "macos", 27 | "sketch", 28 | "palette" 29 | ], 30 | "author": "easylogic", 31 | "license": "MIT", 32 | "bugs": { 33 | "url": "https://github.com/easylogic/codemirror-colorpicker/issues" 34 | }, 35 | "homepage": "https://colorpicker.easylogic.studio/", 36 | "devDependencies": { 37 | "autoprefixer": "^7.2.5", 38 | "babel-cli": "^6.26.0", 39 | "babel-core": "^6.26.0", 40 | "babel-jest": "^22.4.1", 41 | "babel-plugin-external-helpers": "^6.22.0", 42 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 43 | "babel-plugin-transform-object-rest-spread": "^6.26.0", 44 | "babel-preset-env": "^1.6.1", 45 | "babel-preset-es2015": "^6.24.1", 46 | "babel-preset-es2015-rollup": "^3.0.0", 47 | "babel-preset-minify": "^0.2.0", 48 | "codemirror": "^5.48.0", 49 | "cross-env": "^5.1.1", 50 | "http-server": "^0.11.1", 51 | "jest": "^22.4.2", 52 | "jest-cli": "^22.4.2", 53 | "jest-report": "^0.1.11", 54 | "rollup": "^0.52.1", 55 | "rollup-plugin-babel": "^3.0.3", 56 | "rollup-plugin-css-only": "^0.2.0", 57 | "rollup-plugin-glslify": "^1.0.5", 58 | "rollup-plugin-json": "^2.3.0", 59 | "rollup-plugin-livereload": "^0.6.0", 60 | "rollup-plugin-minify": "^1.0.3", 61 | "rollup-plugin-peer-deps-external": "^2.2.0", 62 | "rollup-plugin-postcss": "^1.2.7", 63 | "rollup-plugin-scss": "^0.4.0", 64 | "rollup-plugin-serve": "^0.4.2", 65 | "rollup-plugin-uglify": "^2.0.1", 66 | "rollup-watch": "^4.3.1", 67 | "uglify-es": "^3.2.2" 68 | }, 69 | "peerDependencies": { 70 | "codemirror": "^5.48.0" 71 | }, 72 | "dependencies": {}, 73 | "jest": { 74 | "modulePaths": [ 75 | "/src", 76 | "/node_modules" 77 | ], 78 | "globals": { 79 | "NODE_ENV": "test" 80 | }, 81 | "verbose": false, 82 | "moduleFileExtensions": [ 83 | "js", 84 | "json" 85 | ], 86 | "testRegex": "test/.*\\.spec\\.js$", 87 | "testEnvironment": "node" 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /resources/image/colorpaletts.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/colorpaletts.png -------------------------------------------------------------------------------- /resources/image/colorpicker.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/colorpicker.png -------------------------------------------------------------------------------- /resources/image/grapes.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/grapes.jpg -------------------------------------------------------------------------------- /resources/image/palette-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/palette-type.png -------------------------------------------------------------------------------- /resources/image/scalecolors-title.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/scalecolors-title.png -------------------------------------------------------------------------------- /resources/image/scalecolors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/scalecolors.png -------------------------------------------------------------------------------- /resources/image/screen-shot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/screen-shot.png -------------------------------------------------------------------------------- /resources/image/sketch-type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kode-team/codemirror-colorpicker/f73b1638be8dad4b9d9b2ea7521308b7e136ee53/resources/image/sketch-type.png -------------------------------------------------------------------------------- /src/colorpicker/BaseBox.js: -------------------------------------------------------------------------------- 1 | 2 | import Event from '../util/Event' 3 | import UIElement from './UIElement'; 4 | 5 | export default class BaseBox extends UIElement { 6 | 7 | constructor (opt) { 8 | super(opt) 9 | 10 | this.source = 'base-box' 11 | } 12 | 13 | 14 | refresh () { 15 | 16 | } 17 | 18 | refreshColorUI (e) { 19 | 20 | } 21 | 22 | /** push change event */ 23 | changeColor (opt) { 24 | this.$store.dispatch('/changeColor',Object.assign({ 25 | source: this.source 26 | }, opt || {})) 27 | } 28 | 29 | // Event Bindings 30 | 'mouseup document' (e) { 31 | this.onDragEnd(e); 32 | } 33 | 34 | 'mousemove document' (e) { 35 | this.onDragMove(e); 36 | } 37 | 38 | 'mousedown $bar' (e) { 39 | e.preventDefault(); 40 | this.isDown = true; 41 | } 42 | 43 | 'mousedown $container' (e) { 44 | this.isDown = true 45 | this.onDragStart(e); 46 | } 47 | 48 | 'touchend document' (e) { 49 | this.onDragEnd(e); 50 | } 51 | 52 | 'touchmove document' (e) { 53 | this.onDragMove(e); 54 | } 55 | 56 | 'touchstart $bar' (e) { 57 | e.preventDefault(); 58 | this.isDown = true; 59 | } 60 | 61 | 'touchstart $container' (e) { 62 | this.onDragStart(e); 63 | } 64 | 65 | 66 | onDragStart (e) { 67 | this.isDown = true; 68 | this.refreshColorUI(e); 69 | } 70 | 71 | onDragMove (e) { 72 | if (this.isDown) { 73 | this.refreshColorUI(e); 74 | } 75 | } 76 | 77 | /* called when mouse is ended move */ 78 | onDragEnd (e) { 79 | if (this.isDown) { 80 | this.$store.emit('lastUpdateColor'); 81 | this.isDown = false 82 | } 83 | } 84 | 85 | 86 | '@changeColor' (sourceType) { 87 | if (this.source != sourceType) { 88 | this.refresh() 89 | } 90 | } 91 | 92 | '@initColor' () { this.refresh() } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/colorpicker/BaseModule.js: -------------------------------------------------------------------------------- 1 | export default class BaseModule { 2 | constructor ($store) { 3 | this.$store = $store; 4 | this.initialize(); 5 | } 6 | 7 | initialize() { 8 | this.filterProps().forEach(key => { 9 | this.$store.action(key, this); 10 | }); 11 | } 12 | 13 | filterProps (pattern = '/') { 14 | return Object.getOwnPropertyNames(this.__proto__).filter(key => { 15 | return key.startsWith(pattern); 16 | }); 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/colorpicker/BaseSlider.js: -------------------------------------------------------------------------------- 1 | 2 | import Event from '../util/Event' 3 | import BaseBox from './BaseBox'; 4 | 5 | export default class BaseSlider extends BaseBox { 6 | 7 | constructor (opt) { 8 | super(opt) 9 | 10 | this.minValue = 0 // min domain value 11 | this.maxValue = 1 // max domain value 12 | this.source = 'base-slider' 13 | } 14 | 15 | /* slider container's min and max position */ 16 | getMinMaxPosition () { 17 | var min = this.getMinPosition(); 18 | var width = this.getMaxDist() 19 | var max = min + width; 20 | 21 | return { min, max, width } 22 | } 23 | 24 | /** get current position on page */ 25 | getCurrent (value) { 26 | return min + this.getMaxDist() * value; 27 | } 28 | 29 | /** get min position on slider container */ 30 | getMinPosition () { 31 | return this.refs.$container.offset().left; 32 | } 33 | 34 | getMaxDist () { 35 | return this.state.get('$container.width'); 36 | } 37 | 38 | /** get dist for position value */ 39 | getDist (current) { 40 | var {min, max} = this.getMinMaxPosition() 41 | 42 | var dist; 43 | if (current < min) { 44 | dist = 0; 45 | } else if (current > max) { 46 | dist = 100; 47 | } else { 48 | dist = (current - min) / (max - min) * 100; 49 | } 50 | 51 | return dist; 52 | } 53 | 54 | /** get caculated dist for domain value */ 55 | getCaculatedDist (e) { 56 | var current = e ? this.getMousePosition(e) : this.getCurrent(this.getDefaultValue() / this.maxValue); 57 | var dist = this.getDist(current); 58 | 59 | return dist; 60 | } 61 | 62 | /** get default value used in slider container */ 63 | getDefaultValue () { 64 | return 0 65 | } 66 | 67 | /** set mosue position */ 68 | setMousePosition (x) { 69 | this.refs.$bar.css({ left : (x) + 'px' }); 70 | } 71 | 72 | /** set mouse position in page */ 73 | getMousePosition (e) { 74 | return Event.pos(e).pageX; 75 | } 76 | 77 | refresh () { 78 | this.setColorUI() 79 | } 80 | 81 | /** set drag bar position */ 82 | setColorUI(v) { 83 | 84 | v = v || this.getDefaultValue(); 85 | 86 | if (v <= this.minValue) { 87 | this.refs.$bar.addClass('first').removeClass('last') 88 | } else if (v >= this.maxValue) { 89 | this.refs.$bar.addClass('last').removeClass('first') 90 | } else { 91 | this.refs.$bar.removeClass('last').removeClass('first') 92 | } 93 | 94 | this.setMousePosition(this.getMaxDist() * ( (v || 0) / this.maxValue)); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/colorpicker/BaseStore.js: -------------------------------------------------------------------------------- 1 | export default class BaseStore { 2 | constructor (opt) { 3 | this.callbacks = [] 4 | this.actions = [] 5 | this.modules = opt.modules || [] 6 | 7 | this.initialize() 8 | } 9 | 10 | initialize () { 11 | this.initializeModule(); 12 | } 13 | 14 | initializeModule () { 15 | this.modules.forEach(Module => { 16 | var instance = new Module(this); 17 | }) 18 | } 19 | 20 | action (action, context) { 21 | this.actions[action] = { context, callback: context[action] }; 22 | } 23 | 24 | dispatch (action) { 25 | var args = [...arguments]; 26 | var action = args.shift(); 27 | 28 | var m = this.actions[action]; 29 | 30 | if (m) { 31 | return m.callback.apply(m.context, [this, ...args]); 32 | } 33 | } 34 | 35 | module (ModuleObject) { 36 | // this.action() 37 | } 38 | 39 | on (event, callback) { 40 | this.callbacks.push({ event, callback }) 41 | } 42 | 43 | off (event, callback) { 44 | 45 | if (arguments.length == 0) { 46 | this.callbacks = [] 47 | } else if (arguments.length == 1) { 48 | this.callbacks = this.callbacks.filter(f => { 49 | return f.event != event 50 | }) 51 | } else if (arguments.length == 2) { 52 | this.callbacks = this.callbacks.filter(f => { 53 | return f.event != event && f.callback != callback 54 | }) 55 | } 56 | 57 | } 58 | 59 | emit () { 60 | var args = [...arguments]; 61 | var event = args.shift(); 62 | 63 | this.callbacks.filter(f => { 64 | return (f.event == event) 65 | }).forEach(f => { 66 | if (f && typeof f.callback == 'function') { 67 | f.callback(...args); 68 | } 69 | }) 70 | } 71 | } -------------------------------------------------------------------------------- /src/colorpicker/UIElement.js: -------------------------------------------------------------------------------- 1 | import EventMachin from "../util/EventMachin"; 2 | 3 | const CHECK_STORE_EVENT_PATTERN = /^@/ 4 | 5 | class UIElement extends EventMachin { 6 | constructor (opt) { 7 | super(opt) 8 | 9 | this.opt = opt || {}; 10 | 11 | if (opt && opt.$store) { 12 | this.$store = opt.$store 13 | } 14 | 15 | this.initialize(); 16 | 17 | this.initializeStoreEvent(); 18 | } 19 | 20 | /** 21 | * initialize store event 22 | * 23 | * you can define '@xxx' method(event) in UIElement 24 | * 25 | * 26 | */ 27 | initializeStoreEvent () { 28 | this.storeEvents = {} 29 | this.filterProps(CHECK_STORE_EVENT_PATTERN).forEach((key) => { 30 | const arr = key.split('@') 31 | arr.shift(); 32 | const event = arr.join('@'); 33 | 34 | this.storeEvents[event] = this[key].bind(this) 35 | this.$store.on(event, this.storeEvents[event]); 36 | }); 37 | } 38 | 39 | destoryStoreEvent () { 40 | Object.keys(this.storeEvents).forEach(event => { 41 | this.$store.off(event, this.storeEvents[event]) 42 | }) 43 | } 44 | } 45 | 46 | export default UIElement -------------------------------------------------------------------------------- /src/colorpicker/VerticalSlider.js: -------------------------------------------------------------------------------- 1 | import Event from '../util/Event' 2 | import BaseSlider from "./BaseSlider"; 3 | 4 | export default class VerticalSlider extends BaseSlider { 5 | 6 | constructor (opt) { 7 | super(opt) 8 | 9 | this.source = 'vertical-slider' 10 | } 11 | 12 | /** get max height for vertical slider */ 13 | getMaxDist () { 14 | return this.state.get('$container.height'); 15 | } 16 | 17 | /** set mouse pointer for vertical slider */ 18 | setMousePosition (y) { 19 | this.refs.$bar.css({ top : (y) + 'px' }); 20 | } 21 | 22 | /** get mouse position by pageY for vertical slider */ 23 | getMousePosition (e) { 24 | return Event.pos(e).pageY; 25 | } 26 | 27 | /** get min position for vertial slider */ 28 | getMinPosition () { 29 | return this.refs.$container.offset().top; 30 | } 31 | 32 | /** get caculated dist for domain value */ 33 | getCaculatedDist (e) { 34 | var current = e ? this.getMousePosition(e) : this.getCurrent(this.getDefaultValue() / this.maxValue); 35 | var dist = 100 - this.getDist(current); 36 | 37 | return dist; 38 | } 39 | 40 | /** set drag bar position */ 41 | setColorUI(v) { 42 | 43 | v = v || this.getDefaultValue(); 44 | 45 | if (v <= this.minValue) { 46 | this.refs.$bar.addClass('first').removeClass('last') 47 | } else if (v >= this.maxValue) { 48 | this.refs.$bar.addClass('last').removeClass('first') 49 | } else { 50 | this.refs.$bar.removeClass('last').removeClass('first') 51 | } 52 | 53 | var per = 1 - ( (v || 0) / this.maxValue); 54 | 55 | this.setMousePosition(this.getMaxDist() * per ); 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/colorpicker/box/ColorControl.js: -------------------------------------------------------------------------------- 1 | import { enableEyeDropper } from '../../util/functions/support'; 2 | import Hue from '../ui/control/Hue'; 3 | import Opacity from '../ui/control/Opacity' 4 | import UIElement from '../UIElement'; 5 | import Eyedropper from '../ui/Eyedropper'; 6 | 7 | const source = 'chromedevtool-control'; 8 | 9 | export default class ColorControl extends UIElement { 10 | 11 | components () { 12 | return { Hue, Opacity, Eyedropper } 13 | } 14 | 15 | template () { 16 | 17 | const hasEyeDropper = enableEyeDropper ? 'has-eyedropper' : ''; 18 | let $eyedropper = !!enableEyeDropper ? ` 19 |
20 |
21 |
22 | ` : ''; 23 | 24 | return ` 25 |
26 |
27 | ${$eyedropper} 28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 | 36 |
37 | ` 38 | } 39 | 40 | setBackgroundColor () { 41 | this.refs.$controlColor.css("background-color", this.$store.dispatch('/toRGB')); 42 | } 43 | 44 | refresh () { 45 | this.setColorUI(); 46 | this.setBackgroundColor() 47 | } 48 | 49 | setColorUI() { 50 | this.Hue.setColorUI() 51 | this.Opacity.setColorUI() 52 | } 53 | 54 | '@changeColor' (sourceType) { 55 | if (source != sourceType) { 56 | this.refresh() 57 | } 58 | } 59 | 60 | '@initColor' () { this.refresh() } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /src/colorpicker/box/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | import ColorInformation from '../ui/ColorInformation' 5 | import ColorPalette from '../ui/ColorPalette' 6 | import ColorSetsChooser from '../ui/ColorSetsChooser' 7 | import CurrentColorSets from '../ui/CurrentColorSets' 8 | import CurrentColorSetsContextMenu from '../ui/CurrentColorSetsContextMenu' 9 | 10 | export default class BoxColorPicker extends BaseColorPicker { 11 | 12 | template () { 13 | return /*html*/` 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 | ` 25 | } 26 | 27 | components() { 28 | return { 29 | palette: ColorPalette, 30 | control: ColorControl, 31 | information: ColorInformation, 32 | currentColorSets: CurrentColorSets, 33 | colorSetsChooser: ColorSetsChooser, 34 | contextMenu: CurrentColorSetsContextMenu 35 | } 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /src/colorpicker/chromedevtool/ColorControl.js: -------------------------------------------------------------------------------- 1 | import { enableEyeDropper } from '../../util/functions/support'; 2 | import Hue from '../ui/control/Hue'; 3 | import Opacity from '../ui/control/Opacity' 4 | import UIElement from '../UIElement'; 5 | import Eyedropper from '../ui/Eyedropper'; 6 | 7 | const source = 'chromedevtool-control'; 8 | 9 | export default class ColorControl extends UIElement { 10 | 11 | components () { 12 | return { Hue, Opacity, Eyedropper } 13 | } 14 | 15 | template () { 16 | 17 | const hasEyeDropper = enableEyeDropper ? 'has-eyedropper' : ''; 18 | let $eyedropper = !!enableEyeDropper ? ` 19 |
20 |
21 |
22 | ` : ''; 23 | 24 | return ` 25 |
26 |
27 |
28 |
29 |
30 | ${$eyedropper} 31 |
32 | ` 33 | } 34 | 35 | setBackgroundColor () { 36 | this.refs.$controlColor.css("background-color", this.$store.dispatch('/toRGB')); 37 | } 38 | 39 | refresh () { 40 | this.setColorUI(); 41 | this.setBackgroundColor() 42 | } 43 | 44 | setColorUI() { 45 | this.Hue.setColorUI() 46 | this.Opacity.setColorUI() 47 | } 48 | 49 | '@changeColor' (sourceType) { 50 | if (source != sourceType) { 51 | this.refresh() 52 | } 53 | } 54 | 55 | '@initColor' () { this.refresh() } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/colorpicker/chromedevtool/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | import ColorInformation from '../ui/ColorInformation' 5 | import ColorPalette from '../ui/ColorPalette' 6 | import ColorSetsChooser from '../ui/ColorSetsChooser' 7 | import CurrentColorSets from '../ui/CurrentColorSets' 8 | import CurrentColorSetsContextMenu from '../ui/CurrentColorSetsContextMenu' 9 | 10 | export default class ChromeDevToolColorPicker extends BaseColorPicker { 11 | 12 | template () { 13 | return ` 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ` 23 | } 24 | 25 | components() { 26 | return { 27 | palette: ColorPalette, 28 | control: ColorControl, 29 | information: ColorInformation, 30 | currentColorSets: CurrentColorSets, 31 | colorSetsChooser: ColorSetsChooser, 32 | contextMenu: CurrentColorSetsContextMenu 33 | } 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/colorpicker/index.js: -------------------------------------------------------------------------------- 1 | import MacOSColorPicker from './macos/index' 2 | import ChromeDevToolColorPicker from './chromedevtool/index' 3 | import MiniColorPicker from './mini/index' 4 | import MiniVerticalColorPicker from './mini-vertical/index' 5 | import RingColorPicker from './ring/index' 6 | import XDColorPicker from './xd/index' 7 | import VSCodePicker from './vscode/index' 8 | import BoxColorPicker from './box/index' 9 | 10 | export default { 11 | create (opts) { 12 | switch(opts.type) { 13 | case 'box': 14 | return new BoxColorPicker(opts); 15 | case 'macos': 16 | return new MacOSColorPicker(opts); 17 | case 'xd': 18 | return new XDColorPicker(opts); 19 | case 'ring': 20 | return new RingColorPicker(opts); 21 | case 'mini': 22 | return new MiniColorPicker(opts); 23 | case 'vscode': 24 | return new VSCodePicker(opts); 25 | case 'mini-vertical': 26 | return new MiniVerticalColorPicker(opts); 27 | case 'sketch': 28 | case 'palette': 29 | default: 30 | return new ChromeDevToolColorPicker(opts); 31 | } 32 | }, 33 | ColorPicker: ChromeDevToolColorPicker, 34 | ChromeDevToolColorPicker, 35 | MacOSColorPicker, 36 | RingColorPicker, 37 | MiniColorPicker, 38 | VSCodePicker, 39 | MiniVerticalColorPicker 40 | } -------------------------------------------------------------------------------- /src/colorpicker/macos/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Value from '../ui/control/Value'; 2 | import UIElement from '../UIElement'; 3 | import Opacity from '../ui/control/Opacity' 4 | import Eyedropper from '../ui/Eyedropper'; 5 | import { enableEyeDropper } from '../../util/functions/support'; 6 | 7 | const source = 'macos-control'; 8 | 9 | export default class ColorControl extends UIElement { 10 | 11 | components () { 12 | return { Value, Opacity, Eyedropper } 13 | } 14 | 15 | template () { 16 | 17 | const hasEyeDropper = enableEyeDropper ? 'has-eyedropper' : ''; 18 | let $eyedropper = !!enableEyeDropper ? ` 19 |
20 |
21 |
22 | ` : ''; 23 | 24 | 25 | return ` 26 |
27 |
28 |
29 |
30 |
31 | ${$eyedropper} 32 |
33 | ` 34 | } 35 | 36 | setBackgroundColor () { 37 | this.refs.$controlColor.css("background-color", this.$store.dispatch('/toRGB')); 38 | } 39 | 40 | refresh () { 41 | this.setColorUI(); 42 | this.setBackgroundColor() 43 | } 44 | 45 | setColorUI() { 46 | this.Value.setColorUI() 47 | this.Opacity.setColorUI() 48 | } 49 | 50 | '@changeColor' (sourceType) { 51 | if (source != sourceType) { 52 | this.refresh() 53 | } 54 | } 55 | 56 | '@initColor' () { this.refresh() } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/colorpicker/macos/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | 5 | import ColorWheel from '../ui/ColorWheel' 6 | import ColorInformation from '../ui/ColorInformation' 7 | import ColorSetsChooser from '../ui/ColorSetsChooser' 8 | import CurrentColorSets from '../ui/CurrentColorSets' 9 | import CurrentColorSetsContextMenu from '../ui/CurrentColorSetsContextMenu' 10 | 11 | export default class MacOSColorPicker extends BaseColorPicker { 12 | 13 | template () { 14 | return ` 15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 | ` 24 | } 25 | 26 | components() { 27 | return { 28 | colorwheel: ColorWheel, 29 | control: ColorControl, 30 | information: ColorInformation, 31 | currentColorSets: CurrentColorSets, 32 | colorSetsChooser: ColorSetsChooser, 33 | contextMenu: CurrentColorSetsContextMenu 34 | } 35 | } 36 | 37 | 38 | } -------------------------------------------------------------------------------- /src/colorpicker/mini-vertical/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Hue from '../ui/control/VerticalHue'; 2 | import Opacity from '../ui/control/VerticalOpacity' 3 | import UIElement from '../UIElement'; 4 | 5 | const source = 'mini-control'; 6 | 7 | export default class ColorControl extends UIElement { 8 | 9 | components () { 10 | return { Hue, Opacity } 11 | } 12 | 13 | template () { 14 | return `
` 15 | } 16 | 17 | refresh () { 18 | this.setColorUI(); 19 | } 20 | 21 | setColorUI() { 22 | this.Hue.setColorUI() 23 | this.Opacity.setColorUI() 24 | } 25 | 26 | '@changeColor' (sourceType) { 27 | if (source != sourceType) { 28 | this.refresh() 29 | } 30 | } 31 | 32 | '@initColor' () { this.refresh() } 33 | 34 | } 35 | -------------------------------------------------------------------------------- /src/colorpicker/mini-vertical/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | import ColorPalette from '../ui/ColorPalette' 5 | 6 | export default class MiniColorPicker extends BaseColorPicker { 7 | 8 | template () { 9 | return ` 10 |
11 |
12 |
13 | ` 14 | } 15 | 16 | components() { 17 | return { 18 | palette: ColorPalette, 19 | control: ColorControl 20 | } 21 | } 22 | 23 | } -------------------------------------------------------------------------------- /src/colorpicker/mini/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Hue from '../ui/control/Hue'; 2 | import Opacity from '../ui/control/Opacity' 3 | import UIElement from '../UIElement'; 4 | 5 | const source = 'mini-control'; 6 | 7 | export default class ColorControl extends UIElement { 8 | 9 | components () { 10 | return { Hue, Opacity } 11 | } 12 | 13 | template () { 14 | return ` 15 |
16 |
17 |
18 |
19 | ` 20 | } 21 | 22 | refresh () { 23 | this.setColorUI(); 24 | } 25 | 26 | setColorUI() { 27 | this.Hue.setColorUI() 28 | this.Opacity.setColorUI() 29 | } 30 | 31 | '@changeColor' (sourceType) { 32 | if (source != sourceType) { 33 | this.refresh() 34 | } 35 | } 36 | 37 | '@initColor' () { this.refresh() } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/colorpicker/mini/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | import ColorPalette from '../ui/ColorPalette' 5 | 6 | export default class MiniColorPicker extends BaseColorPicker { 7 | 8 | template () { 9 | return ` 10 |
11 |
12 |
13 |
14 | ` 15 | } 16 | 17 | components() { 18 | return { 19 | palette: ColorPalette, 20 | control: ColorControl 21 | } 22 | } 23 | 24 | } -------------------------------------------------------------------------------- /src/colorpicker/module/ColorManager.js: -------------------------------------------------------------------------------- 1 | import Color from '../../util/Color' 2 | import HueColor from '../../util/HueColor' 3 | import BaseModule from '../BaseModule'; 4 | 5 | 6 | function isUndefined (v) { 7 | return typeof v == 'undefined' || v == null; 8 | } 9 | 10 | export default class ColorManager extends BaseModule { 11 | 12 | initialize () { 13 | super.initialize() 14 | 15 | this.$store.rgb = {} 16 | this.$store.hsl = {} 17 | this.$store.hsv = {} 18 | this.$store.alpha = 1 19 | this.$store.format = 'hex' 20 | 21 | // this.$store.dispatch('/changeColor'); 22 | } 23 | 24 | '/changeFormat' ($store, format) { 25 | $store.format = format; 26 | 27 | $store.emit('changeFormat'); 28 | } 29 | 30 | '/initColor' ($store, colorObj, source) { 31 | $store.dispatch('/changeColor', colorObj, source, true); 32 | $store.emit('initColor') 33 | } 34 | 35 | '/changeColor' ($store, colorObj, source, isNotEmit) { 36 | 37 | colorObj = colorObj || '#FF0000' 38 | 39 | if (typeof colorObj == 'string') { 40 | colorObj = Color.parse(colorObj); 41 | } 42 | 43 | colorObj.source = colorObj.source || source 44 | 45 | $store.alpha = isUndefined(colorObj.a) ? $store.alpha : colorObj.a; 46 | $store.format = colorObj.type != 'hsv' ? (colorObj.type || $store.format) : $store.format; 47 | 48 | if (colorObj.type == 'hsl') { 49 | $store.hsl = Object.assign($store.hsl, colorObj); 50 | $store.rgb = Color.HSLtoRGB($store.hsl); 51 | $store.hsv = Color.HSLtoHSV(colorObj); 52 | } else if (colorObj.type == 'hex') { 53 | $store.rgb = Object.assign($store.rgb, colorObj); 54 | $store.hsl = Color.RGBtoHSL($store.rgb); 55 | $store.hsv = Color.RGBtoHSV(colorObj); 56 | } else if (colorObj.type == 'rgb') { 57 | $store.rgb = Object.assign($store.rgb, colorObj); 58 | $store.hsl = Color.RGBtoHSL($store.rgb); 59 | $store.hsv = Color.RGBtoHSV(colorObj); 60 | } else if (colorObj.type == 'hsv') { 61 | $store.hsv = Object.assign($store.hsv, colorObj); 62 | $store.rgb = Color.HSVtoRGB($store.hsv); 63 | $store.hsl = Color.HSVtoHSL($store.hsv); 64 | } 65 | 66 | if (!isNotEmit) { 67 | $store.emit('changeColor', colorObj.source); 68 | } 69 | 70 | } 71 | 72 | '/getHueColor' ($store) { 73 | return HueColor.checkHueColor($store.hsv.h/360); 74 | } 75 | 76 | '/toString' ($store, type) { 77 | type = type || $store.format 78 | var colorObj = $store[type] || $store.rgb 79 | return Color.format({ 80 | ...colorObj, 81 | a: $store.alpha 82 | }, type); 83 | } 84 | 85 | '/toColor' ($store, type) { 86 | type = type || $store.format; 87 | 88 | if (type == 'rgb') { 89 | return $store.dispatch('/toRGB') 90 | } else if (type == 'hsl') { 91 | return $store.dispatch('/toHSL') 92 | } else if (type == 'hex') { 93 | return $store.dispatch('/toHEX') 94 | } 95 | 96 | return $store.dispatch('/toString', type); 97 | } 98 | 99 | '/toRGB' ($store) { 100 | return $store.dispatch('/toString', 'rgb') 101 | } 102 | 103 | '/toHSL' ($store) { 104 | return $store.dispatch('/toString', 'hsl') 105 | } 106 | 107 | '/toHEX' ($store) { 108 | return $store.dispatch('/toString', 'hex').toUpperCase() 109 | } 110 | 111 | } -------------------------------------------------------------------------------- /src/colorpicker/ring/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Value from '../ui/control/Value'; 2 | import UIElement from '../UIElement'; 3 | import Opacity from '../ui/control/Opacity' 4 | import { enableEyeDropper } from '../../util/functions/support'; 5 | import Eyedropper from '../ui/Eyedropper'; 6 | 7 | const source = 'macos-control'; 8 | 9 | export default class ColorControl extends UIElement { 10 | 11 | components () { 12 | return { Value, Opacity, Eyedropper } 13 | } 14 | 15 | template () { 16 | 17 | const hasEyeDropper = enableEyeDropper ? 'has-eyedropper' : ''; 18 | let $eyedropper = !!enableEyeDropper ? ` 19 |
20 |
21 |
22 | ` : ''; 23 | 24 | return ` 25 |
26 |
27 |
28 |
29 |
30 | ${$eyedropper} 31 |
32 | ` 33 | } 34 | 35 | setBackgroundColor () { 36 | this.refs.$controlColor.css("background-color", this.$store.dispatch('/toRGB')); 37 | } 38 | 39 | refresh () { 40 | this.setColorUI(); 41 | this.setBackgroundColor() 42 | } 43 | 44 | setColorUI() { 45 | this.Value.setColorUI() 46 | this.Opacity.setColorUI() 47 | } 48 | 49 | '@changeColor' (sourceType) { 50 | if (source != sourceType) { 51 | this.refresh() 52 | } 53 | } 54 | 55 | '@initColor' () { this.refresh() } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /src/colorpicker/ring/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | 5 | // import ColorWheel from '../ui/ColorWheel' 6 | import ColorInformation from '../ui/ColorInformation' 7 | import ColorSetsChooser from '../ui/ColorSetsChooser' 8 | import CurrentColorSets from '../ui/CurrentColorSets' 9 | import CurrentColorSetsContextMenu from '../ui/CurrentColorSetsContextMenu' 10 | import ColorRing from '../ui/ColorRing'; 11 | import ColorPalette from '../ui/ColorPalette'; 12 | 13 | export default class RingColorPicker extends BaseColorPicker { 14 | 15 | template () { 16 | return ` 17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | ` 27 | } 28 | 29 | components() { 30 | return { 31 | colorring: ColorRing, 32 | palette: ColorPalette, 33 | control: ColorControl, 34 | information: ColorInformation, 35 | currentColorSets: CurrentColorSets, 36 | colorSetsChooser: ColorSetsChooser, 37 | contextMenu: CurrentColorSetsContextMenu 38 | } 39 | } 40 | 41 | 42 | } -------------------------------------------------------------------------------- /src/colorpicker/ui/ColorPalette.js: -------------------------------------------------------------------------------- 1 | import UIElement from '../UIElement'; 2 | import Event from '../../util/Event' 3 | 4 | const source = 'chromedevtool-palette'; 5 | 6 | export default class ColorPalette extends UIElement { 7 | 8 | template () { 9 | return ` 10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | ` 18 | } 19 | 20 | setBackgroundColor (color) { 21 | this.$el.css("background-color", color); 22 | } 23 | 24 | refresh () { 25 | this.setColorUI(); 26 | } 27 | 28 | caculateSV () { 29 | var pos = this.drag_pointer_pos || { x : 0, y : 0 }; 30 | 31 | var width = this.state.get('$el.width'); 32 | var height = this.state.get('$el.height'); 33 | 34 | var s = (pos.x / width); 35 | var v = ((height - pos.y) / height); 36 | 37 | this.$store.dispatch('/changeColor', { 38 | type: 'hsv', 39 | s, 40 | v, 41 | source 42 | }) 43 | } 44 | 45 | setColorUI() { 46 | var x = this.state.get('$el.width') * this.$store.hsv.s, 47 | y = this.state.get('$el.height') * ( 1 - this.$store.hsv.v ); 48 | 49 | this.refs.$drag_pointer.css({ 50 | left : x + "px", 51 | top : y + "px" 52 | }); 53 | 54 | this.drag_pointer_pos = { x , y }; 55 | 56 | this.setBackgroundColor(this.$store.dispatch('/getHueColor')) 57 | } 58 | 59 | 60 | setMainColor(e) { 61 | // e.preventDefault(); 62 | var pos = this.$el.offset(); // position for screen 63 | var w = this.state.get('$el.contentWidth'); 64 | var h = this.state.get('$el.contentHeight'); 65 | 66 | var x = Event.pos(e).pageX - pos.left; 67 | var y = Event.pos(e).pageY - pos.top; 68 | 69 | if (x < 0) x = 0; 70 | else if (x > w) x = w; 71 | 72 | if (y < 0) y = 0; 73 | else if (y > h) y = h; 74 | 75 | this.refs.$drag_pointer.css({ 76 | left: x + 'px', 77 | top: y + 'px' 78 | }); 79 | 80 | this.drag_pointer_pos = { x , y } 81 | 82 | this.caculateSV() 83 | } 84 | 85 | '@changeColor' (sourceType) { 86 | if (source != sourceType) { 87 | this.refresh() 88 | } 89 | } 90 | 91 | '@initColor' () { this.refresh() } 92 | 93 | 'mouseup document' (e) { 94 | if (this.isDown) { 95 | this.isDown = false; 96 | this.$store.emit('lastUpdateColor'); 97 | } 98 | } 99 | 100 | 'mousemove document' (e) { 101 | if (this.isDown) { 102 | this.setMainColor(e); 103 | } 104 | } 105 | 106 | mousedown (e) { 107 | this.isDown = true; 108 | this.setMainColor(e); 109 | } 110 | 111 | 'touchend document' (e) { 112 | if (this.isDown) { 113 | this.isDown = false; 114 | this.$store.emit('lastUpdateColor'); 115 | } 116 | } 117 | 118 | 'touchmove document' (e) { 119 | if (this.isDown) { 120 | this.setMainColor(e); 121 | } 122 | } 123 | 124 | touchstart (e) { 125 | e.preventDefault() 126 | this.isDown = true; 127 | this.setMainColor(e); 128 | } 129 | 130 | } 131 | -------------------------------------------------------------------------------- /src/colorpicker/ui/ColorRing.js: -------------------------------------------------------------------------------- 1 | import ColorWheel from './ColorWheel'; 2 | import { caculateAngle } from '../../util/functions/math'; 3 | 4 | export default class ColorRing extends ColorWheel { 5 | 6 | constructor (opt) { 7 | super(opt) 8 | 9 | this.width = 214; 10 | this.height = 214; 11 | this.thinkness = 16; 12 | this.half_thinkness = this.thinkness / 2 13 | this.source = 'colorring' 14 | } 15 | 16 | template () { 17 | return ` 18 |
19 | 20 |
21 |
22 | ` 23 | } 24 | 25 | setColorUI(isEvent) { 26 | this.renderCanvas(); 27 | this.setHueColor(null, isEvent); 28 | } 29 | 30 | getDefaultValue () { 31 | return this.$store.hsv.h 32 | } 33 | 34 | setHueColor (e, isEvent) { 35 | 36 | if (!this.state.get('$el.width')) return; 37 | 38 | var { minX, minY, radius, centerX, centerY } = this.getRectangle() 39 | var { x , y } = this.getCurrentXY( 40 | e, 41 | this.getDefaultValue(), 42 | radius, 43 | centerX, 44 | centerY 45 | ) 46 | 47 | var rx = x - centerX, ry = y - centerY, hue = caculateAngle(rx, ry); 48 | 49 | { 50 | var { x, y } = this.getCurrentXY(null, hue, radius - this.half_thinkness, centerX, centerY); 51 | } 52 | 53 | 54 | // set drag pointer position 55 | this.refs.$drag_pointer.css({ 56 | left: (x - minX) + 'px', 57 | top: (y - minY) + 'px' 58 | }); 59 | 60 | if (!isEvent) { 61 | this.changeColor({ 62 | type: 'hsv', 63 | h: hue 64 | }) 65 | } 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/colorpicker/ui/ColorSetsChooser.js: -------------------------------------------------------------------------------- 1 | import UIElement from '../UIElement'; 2 | 3 | const DATA_COLORSETS_INDEX = 'data-colorsets-index'; 4 | 5 | export default class ColorSetsChooser extends UIElement { 6 | 7 | template () { 8 | return ` 9 |
10 |
11 |
12 |

Color Palettes

13 | × 14 |
15 |
16 |
17 |
18 | ` 19 | } 20 | 21 | refresh () { 22 | this.load(); 23 | } 24 | 25 | '@changeCurrentColorSets' () { 26 | this.refresh() 27 | } 28 | 29 | '@toggleColorChooser' () { 30 | this.toggle() 31 | } 32 | 33 | // loadable 34 | 'load $colorsetsList' () { 35 | // colorsets 36 | const colorSets = this.$store.dispatch('/getColorSetsList'); 37 | 38 | return ` 39 |
40 | ${colorSets.map( (element, index) => { 41 | return ` 42 |
43 |

${element.name}

44 |
45 |
46 | ${element.colors.filter((color, i) => i < 5).map(color => { 47 | color = color || 'rgba(255, 255, 255, 1)'; 48 | return `
49 |
50 |
` 51 | }).join('')} 52 |
53 |
54 |
` 55 | }).join('')} 56 |
57 | ` 58 | } 59 | 60 | show () { 61 | this.$el.addClass('open'); 62 | } 63 | 64 | hide () { 65 | this.$el.removeClass('open'); 66 | } 67 | 68 | toggle () { 69 | this.$el.toggleClass('open'); 70 | } 71 | 72 | 73 | 'click $toggleButton' (e) { 74 | this.toggle(); 75 | } 76 | 77 | 'click $colorsetsList .colorsets-item' (e) { 78 | const $item = e.$delegateTarget; 79 | 80 | if ($item) { 81 | 82 | const index = parseInt($item.attr(DATA_COLORSETS_INDEX)); 83 | 84 | this.$store.dispatch('/setCurrentColorSets', index); 85 | 86 | this.hide(); 87 | } 88 | } 89 | 90 | destroy () { 91 | super.destroy(); 92 | 93 | this.hide(); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/colorpicker/ui/CurrentColorSets.js: -------------------------------------------------------------------------------- 1 | import Dom from '../../util/Dom' 2 | import UIElement from '../UIElement'; 3 | 4 | export default class CurrentColorSets extends UIElement { 5 | 6 | template() { 7 | return ` 8 |
9 | 12 |
13 |
14 | ` 15 | } 16 | 17 | 'load $colorSetsColorList' () { 18 | const currentColorSets = this.$store.dispatch('/getCurrentColorSets') 19 | const colors = this.$store.dispatch('/getCurrentColors') 20 | 21 | return ` 22 |
23 | ${colors.map( (color, i) => { 24 | return `
25 |
26 |
27 |
` 28 | }).join('')} 29 | ${currentColorSets.edit ? `
+
` : ''} 30 |
31 | ` 32 | } 33 | 34 | refresh () { 35 | this.load(); 36 | } 37 | 38 | 39 | addColor (color) { 40 | this.$store.dispatch('/addCurrentColor', color); 41 | } 42 | 43 | '@changeCurrentColorSets' () { 44 | this.refresh() 45 | } 46 | 47 | 'click $colorSetsChooseButton' (e) { 48 | this.$store.emit('toggleColorChooser'); 49 | } 50 | 51 | 'contextmenu $colorSetsColorList' (e) { 52 | e.preventDefault(); 53 | const currentColorSets = this.$store.dispatch('/getCurrentColorSets') 54 | 55 | if (!currentColorSets.edit) { 56 | return; 57 | } 58 | 59 | const $target = new Dom(e.target); 60 | 61 | const $item = $target.closest('color-item'); 62 | 63 | if ($item) { 64 | const index = parseInt($item.attr('data-index')); 65 | 66 | this.$store.emit('showContextMenu', e, index); 67 | } else { 68 | this.$store.emit('showContextMenu', e); 69 | } 70 | } 71 | 72 | 'click $colorSetsColorList .add-color-item' (e) { 73 | this.addColor(this.$store.dispatch('/toColor')); 74 | } 75 | 76 | 'click $colorSetsColorList .color-item' (e) { 77 | this.$store.dispatch('/changeColor', e.$delegateTarget.attr('data-color')); 78 | this.$store.emit('lastUpdateColor') 79 | } 80 | 81 | } 82 | -------------------------------------------------------------------------------- /src/colorpicker/ui/CurrentColorSetsContextMenu.js: -------------------------------------------------------------------------------- 1 | import Event from '../../util/Event' 2 | import UIElement from '../UIElement'; 3 | 4 | export default class CurrentColorSetsContextMenu extends UIElement { 5 | 6 | template () { 7 | return ` 8 | 13 | ` 14 | } 15 | 16 | show (e, index) { 17 | const $event = Event.pos(e); 18 | 19 | this.$el.css({ 20 | top: ($event.clientY - 10) + 'px', 21 | left: $event.clientX + 'px' 22 | }); 23 | this.$el.addClass('show'); 24 | this.selectedColorIndex = index; 25 | 26 | if (typeof this.selectedColorIndex == 'undefined') { 27 | this.$el.addClass('small') 28 | } else { 29 | this.$el.removeClass('small') 30 | } 31 | 32 | } 33 | 34 | hide () { 35 | this.$el.removeClass('show'); 36 | } 37 | 38 | runCommand (command) { 39 | switch(command) { 40 | case 'remove-color': 41 | this.$store.dispatch('/removeCurrentColor', this.selectedColorIndex); 42 | break; 43 | case 'remove-all-to-the-right': 44 | this.$store.dispatch('/removeCurrentColorToTheRight', this.selectedColorIndex); 45 | break; 46 | case 'clear-palette': 47 | this.$store.dispatch('/clearPalette'); 48 | break; 49 | } 50 | } 51 | 52 | '@showContextMenu' (e, index) { 53 | this.show(e, index) 54 | } 55 | 56 | 'click $el .menu-item' (e) { 57 | e.preventDefault(); 58 | 59 | this.runCommand(e.$delegateTarget.attr('data-type')); 60 | this.hide(); 61 | } 62 | 63 | } 64 | -------------------------------------------------------------------------------- /src/colorpicker/ui/Eyedropper.js: -------------------------------------------------------------------------------- 1 | 2 | import UIElement from '../UIElement'; 3 | import './Eyedropper.scss'; 4 | import { enableEyeDropper } from '../../util/functions/support'; 5 | 6 | export default class Eyedropper extends UIElement { 7 | 8 | template() { 9 | return /*html*/` 10 | 17 | `; 18 | } 19 | 20 | ['click $button']() { 21 | if (enableEyeDropper) { 22 | const eyeDropper = new EyeDropper(); 23 | eyeDropper.open().then(result => { 24 | this.$store.dispatch('/changeColor', result.sRGBHex); 25 | this.$store.emit('lastUpdateColor'); 26 | }) 27 | 28 | 29 | } 30 | } 31 | 32 | } -------------------------------------------------------------------------------- /src/colorpicker/ui/Eyedropper.scss: -------------------------------------------------------------------------------- 1 | .el-cp-color-eyedropper { 2 | button { 3 | display: block; 4 | width: 30px; 5 | height: 30px; 6 | padding: 0; 7 | margin: -4px; 8 | font-size: 0; 9 | border: none; 10 | border-radius: var(--size-radius); 11 | cursor: pointer; 12 | outline: none; 13 | box-sizing: border-box; 14 | background: none; 15 | transition: box-shadow var(--speed-focus) ease-out, opacity var(--speed-focus) ease-out; 16 | &:focus-visible { 17 | box-shadow: 0 0 0 2px var(--color-key); 18 | } 19 | &:active { 20 | opacity: .5; 21 | } 22 | } 23 | svg { 24 | display: block; 25 | margin: 0 auto; 26 | color: var(--color-fill); 27 | } 28 | } -------------------------------------------------------------------------------- /src/colorpicker/ui/control/Hue.js: -------------------------------------------------------------------------------- 1 | import BaseSlider from '../../BaseSlider'; 2 | 3 | export default class Hue extends BaseSlider { 4 | 5 | constructor (opt) { 6 | super(opt) 7 | 8 | this.minValue = 0 9 | this.maxValue = 360 10 | this.source = 'hue-control' 11 | } 12 | 13 | template () { 14 | return ` 15 |
16 |
17 |
18 |
19 |
20 | ` 21 | } 22 | 23 | getDefaultValue () { 24 | return this.$store.hsv.h 25 | } 26 | 27 | refreshColorUI(e) { 28 | 29 | var dist = this.getCaculatedDist(e); 30 | 31 | this.setColorUI(dist/100 * this.maxValue); 32 | 33 | this.changeColor({ 34 | h: (dist/100) * this.maxValue, 35 | type: 'hsv' 36 | }) 37 | } 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/colorpicker/ui/control/Opacity.js: -------------------------------------------------------------------------------- 1 | 2 | import Color from '../../../util/Color' 3 | import Event from '../../../util/Event' 4 | import BaseSlider from '../../BaseSlider'; 5 | 6 | const source = 'chromedevtool-control-Opacity'; 7 | 8 | export default class Opacity extends BaseSlider { 9 | 10 | constructor (opt) { 11 | super(opt); 12 | 13 | this.minValue = 0; 14 | this.maxValue = 1; 15 | this.source = 'opacity-control' 16 | } 17 | 18 | template () { 19 | return ` 20 |
21 |
22 |
23 |
24 |
25 |
26 | ` 27 | } 28 | 29 | refresh () { 30 | super.refresh() 31 | this.setOpacityColorBar() 32 | } 33 | 34 | setOpacityColorBar() { 35 | var rgb = Object.assign({}, this.$store.rgb); 36 | 37 | rgb.a = 0; 38 | var start = Color.format(rgb, 'rgb'); 39 | 40 | rgb.a = 1; 41 | var end = Color.format(rgb, 'rgb'); 42 | 43 | this.setOpacityColorBarBackground(start, end); 44 | } 45 | 46 | setOpacityColorBarBackground(start, end) { 47 | this.refs.$colorbar.css('background', 'linear-gradient(to right, ' + start + ', ' + end + ')'); 48 | } 49 | 50 | getDefaultValue () { 51 | return this.$store.alpha 52 | } 53 | 54 | refreshColorUI(e) { 55 | var dist = this.getCaculatedDist(e); 56 | 57 | this.setColorUI( (dist/100) * this.maxValue); 58 | 59 | this.changeColor({ 60 | a: (Math.floor(dist) / 100) * this.maxValue 61 | }) 62 | 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/colorpicker/ui/control/Value.js: -------------------------------------------------------------------------------- 1 | 2 | import Event from '../../../util/Event' 3 | import BaseSlider from '../../BaseSlider'; 4 | 5 | export default class Value extends BaseSlider { 6 | 7 | constructor (opt) { 8 | super(opt) 9 | 10 | this.minValue = 0 11 | this.maxValue = 1 12 | this.source = 'value-control' 13 | } 14 | 15 | template () { 16 | return ` 17 |
18 |
19 |
20 |
21 |
22 | ` 23 | } 24 | 25 | setBackgroundColor () { 26 | this.refs.$container.css("background-color", this.$store.dispatch('/toRGB')); 27 | } 28 | 29 | 30 | refresh () { 31 | super.refresh() 32 | this.setBackgroundColor(); 33 | } 34 | 35 | getDefaultValue () { 36 | return this.$store.hsv.v 37 | } 38 | 39 | refreshColorUI(e) { 40 | var dist = this.getCaculatedDist(e); 41 | 42 | this.setColorUI(dist/100 * this.maxValue) 43 | 44 | this.changeColor({ 45 | type: 'hsv', 46 | v: dist/100 * this.maxValue 47 | }) 48 | } 49 | 50 | } 51 | -------------------------------------------------------------------------------- /src/colorpicker/ui/control/VerticalHue.js: -------------------------------------------------------------------------------- 1 | import VerticalSlider from '../../VerticalSlider'; 2 | 3 | export default class VerticalHue extends VerticalSlider { 4 | 5 | constructor (opt) { 6 | super(opt) 7 | 8 | this.minValue = 0 9 | this.maxValue = 360 10 | this.source = 'vertical-hue-control' 11 | } 12 | 13 | template () { 14 | return ` 15 |
16 |
17 |
18 |
19 |
20 | ` 21 | } 22 | 23 | getDefaultValue () { 24 | return this.$store.hsv.h 25 | } 26 | 27 | refreshColorUI(e) { 28 | 29 | var dist = this.getCaculatedDist(e) 30 | 31 | this.setColorUI( dist/100 * this.maxValue); 32 | 33 | this.changeColor({ 34 | h: (dist/100) * this.maxValue, 35 | type: 'hsv' 36 | }) 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/colorpicker/ui/control/VerticalOpacity.js: -------------------------------------------------------------------------------- 1 | 2 | import Color from '../../../util/Color' 3 | import Event from '../../../util/Event' 4 | import VerticalSlider from '../../VerticalSlider'; 5 | 6 | export default class Opacity extends VerticalSlider { 7 | 8 | constructor (opt) { 9 | super(opt) 10 | 11 | this.source = 'vertical-opacity-control' 12 | } 13 | 14 | template () { 15 | return ` 16 |
17 |
18 |
19 |
20 |
21 |
22 | ` 23 | } 24 | 25 | refresh () { 26 | super.refresh() 27 | this.setOpacityColorBar() 28 | } 29 | 30 | setOpacityColorBar() { 31 | var rgb = Object.assign({}, this.$store.rgb); 32 | 33 | rgb.a = 0; 34 | var start = Color.format(rgb, 'rgb'); 35 | 36 | rgb.a = 1; 37 | var end = Color.format(rgb, 'rgb'); 38 | 39 | this.refs.$colorbar.css('background', 'linear-gradient(to top, ' + start + ', ' + end + ')'); 40 | } 41 | 42 | getDefaultValue () { 43 | return this.$store.alpha 44 | } 45 | 46 | refreshColorUI(e) { 47 | var dist = this.getCaculatedDist(e) 48 | 49 | this.setColorUI( ( dist/100 * this.maxValue) ); 50 | 51 | this.changeColor({ 52 | a: Math.floor(dist) / 100 * this.maxValue 53 | }) 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/colorpicker/vscode/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Hue from '../ui/control/VerticalHue'; 2 | import Opacity from '../ui/control/VerticalOpacity' 3 | import UIElement from '../UIElement'; 4 | 5 | const source = 'mini-control'; 6 | 7 | export default class ColorControl extends UIElement { 8 | 9 | components () { 10 | return { Hue, Opacity } 11 | } 12 | 13 | template () { 14 | return /*html*/` 15 |
16 |
17 |
18 |
19 | ` 20 | } 21 | 22 | refresh () { 23 | this.setColorUI(); 24 | } 25 | 26 | setColorUI() { 27 | this.Hue.setColorUI() 28 | this.Opacity.setColorUI() 29 | } 30 | 31 | '@changeColor' (sourceType) { 32 | if (source != sourceType) { 33 | this.refresh() 34 | } 35 | } 36 | 37 | '@initColor' () { this.refresh() } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/colorpicker/vscode/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | import ColorPalette from '../ui/ColorPalette' 5 | import Color from '../../util/Color' 6 | import { enableEyeDropper } from '../../util/functions/support'; 7 | import Eyedropper from '../ui/Eyedropper'; 8 | 9 | export default class VSCodePicker extends BaseColorPicker { 10 | 11 | template () { 12 | 13 | const hasEyeDropper = enableEyeDropper ? 'has-eyedropper' : ''; 14 | let $eyedropper = !!enableEyeDropper ? ` 15 |
16 |
17 |
18 | ` : ''; 19 | 20 | return /*html*/` 21 |
22 |
23 |
24 |
25 |
26 | ${$eyedropper} 27 |
28 |
29 |
30 |
31 |
32 |
33 | ` 34 | } 35 | 36 | components() { 37 | return { 38 | palette: ColorPalette, 39 | control: ColorControl, 40 | Eyedropper 41 | } 42 | } 43 | 44 | initColorWithoutChangeEvent (color) { 45 | this.$store.dispatch('/initColor', color); 46 | this.refresh(); 47 | } 48 | 49 | setBackgroundColor () { 50 | var color = this.$store.dispatch('/toColor') 51 | var rgb = this.$store.rgb; 52 | var bValue = Color.brightness(rgb.r,rgb.g,rgb.b); 53 | 54 | this.refs.$colorview.css({ 55 | "background-color": color, 56 | 'color': bValue > 127 ? 'black': 'white' 57 | }); 58 | this.refs.$colorview.html(color); 59 | } 60 | 61 | 'click $colorview' (e) { 62 | this.nextFormat() 63 | } 64 | 65 | nextFormat() { 66 | var current_format = this.$store.format || 'hex'; 67 | 68 | var next_format = 'hex'; 69 | if (current_format == 'hex') { 70 | next_format = 'rgb'; 71 | } else if (current_format == 'rgb') { 72 | next_format = 'hsl'; 73 | } else if (current_format == 'hsl') { 74 | next_format = 'hex'; 75 | } 76 | 77 | this.$store.dispatch('/changeFormat', next_format); 78 | this.$store.emit('lastUpdateColor') 79 | this.refresh(); 80 | } 81 | 82 | refresh () { 83 | this.setBackgroundColor() 84 | } 85 | 86 | '@changeColor' () { 87 | this.refresh() 88 | } 89 | 90 | '@initColor' () { 91 | this.refresh() 92 | } 93 | 94 | 95 | 96 | } -------------------------------------------------------------------------------- /src/colorpicker/xd/ColorControl.js: -------------------------------------------------------------------------------- 1 | import Hue from '../ui/control/VerticalHue'; 2 | import Opacity from '../ui/control/VerticalOpacity' 3 | import UIElement from '../UIElement'; 4 | 5 | export default class ColorControl extends UIElement { 6 | 7 | components () { 8 | return { Hue, Opacity } 9 | } 10 | 11 | template () { 12 | return ` 13 |
14 |
15 |
16 |
17 | ` 18 | } 19 | 20 | refresh () { 21 | this.setColorUI(); 22 | } 23 | 24 | setColorUI() { 25 | this.Hue.setColorUI() 26 | this.Opacity.setColorUI() 27 | } 28 | 29 | '@changeColor' () { 30 | this.refresh() 31 | } 32 | 33 | '@initColor' () { this.refresh() } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /src/colorpicker/xd/index.js: -------------------------------------------------------------------------------- 1 | import BaseColorPicker from '../BaseColorPicker' 2 | 3 | import ColorControl from './ColorControl' 4 | import ColorInformation from '../ui/ColorInformation' 5 | import ColorPalette from '../ui/ColorPalette' 6 | import ColorSetsChooser from '../ui/ColorSetsChooser' 7 | import CurrentColorSets from '../ui/CurrentColorSets' 8 | import CurrentColorSetsContextMenu from '../ui/CurrentColorSetsContextMenu' 9 | 10 | export default class XDColorPicker extends BaseColorPicker { 11 | 12 | template () { 13 | return ` 14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | ` 23 | } 24 | 25 | components() { 26 | return { 27 | palette: ColorPalette, 28 | control: ColorControl, 29 | information: ColorInformation, 30 | currentColorSets: CurrentColorSets, 31 | colorSetsChooser: ColorSetsChooser, 32 | contextMenu: CurrentColorSetsContextMenu 33 | } 34 | } 35 | 36 | } -------------------------------------------------------------------------------- /src/extension/codemirror/index.js: -------------------------------------------------------------------------------- 1 | import CodeMirrorColorView from './colorview' 2 | 3 | try { 4 | var CodeMirror = require('codemirror') 5 | } catch(e) { } 6 | 7 | const CHECK_CODEMIRROR_OBJECT = () => (CodeMirror || window.CodeMirror); 8 | function LOAD_CODEMIRROR_COLORPICKER () { 9 | var CODEMIRROR_OBJECT = CHECK_CODEMIRROR_OBJECT(); 10 | 11 | if (CODEMIRROR_OBJECT) { 12 | CODEMIRROR_OBJECT.defineOption("colorpicker", false, function (cm, val, old) { 13 | if (old && old != CODEMIRROR_OBJECT.Init) { 14 | 15 | if (cm.state.colorpicker) 16 | { 17 | cm.state.colorpicker.destroy(); 18 | cm.state.colorpicker = null; 19 | 20 | } 21 | // remove event listener 22 | } 23 | 24 | if (val) 25 | { 26 | cm.state.colorpicker = new CodeMirrorColorView(cm, val); 27 | } 28 | }); 29 | } 30 | 31 | } 32 | 33 | LOAD_CODEMIRROR_COLORPICKER() 34 | 35 | export default { 36 | load: LOAD_CODEMIRROR_COLORPICKER 37 | } -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './scss/index.scss' 2 | 3 | import Util from './util/index' 4 | import ColorPicker from './colorpicker/index' 5 | import CodeMirrorExtension from './extension/codemirror/index' 6 | 7 | 8 | export default { 9 | ...Util, 10 | ...ColorPicker, 11 | ...CodeMirrorExtension 12 | } -------------------------------------------------------------------------------- /src/scss/colorpicker.scss: -------------------------------------------------------------------------------- 1 | 2 | /* codemirror-colorpicker */ 3 | 4 | .codemirror-colorpicker { 5 | position: relative; 6 | width: 224px; 7 | z-index: 1000; 8 | display:inline-block; 9 | border: 1px solid rgba(0, 0, 0, 0.2); 10 | background-color: #fff; 11 | border-radius: 3px; 12 | box-shadow: 0 0px 10px 2px rgba(0, 0, 0, 0.12); 13 | 14 | > .arrow { 15 | position: absolute; 16 | top: -10px; 17 | left: 7px; 18 | width: 0; 19 | height: 0; 20 | border-left: 10px solid transparent; 21 | border-right: 10px solid transparent; 22 | display:none; 23 | 24 | border-bottom: 10px solid rgba(0, 0, 0, 0.2); 25 | pointer-events: none; 26 | &:after { 27 | position: absolute; 28 | content: ""; 29 | top: 1px; 30 | left: -9px; 31 | width: 0; 32 | height: 0; 33 | border-left: 9px solid transparent; 34 | border-right: 9px solid transparent; 35 | 36 | border-bottom: 9px solid white; 37 | } 38 | } 39 | 40 | .colorpicker-body { 41 | @import './component/button'; 42 | @import './component/palette'; 43 | @import './component/control'; 44 | @import './component/information'; 45 | @import './component/colorsets'; 46 | @import './component/colorchooser'; 47 | 48 | } 49 | 50 | &.chromedevtool { 51 | 52 | } 53 | 54 | /* theme */ 55 | @import './themes/sketch'; 56 | @import './themes/palette'; 57 | @import './themes/macos'; 58 | @import './themes/mini'; 59 | @import './themes/mini-vertical'; 60 | @import './themes/ring'; 61 | @import './themes/xd'; 62 | @import './themes/vscode'; 63 | @import './themes/box'; 64 | } 65 | 66 | @import './component/colorsets-contextmenu'; 67 | -------------------------------------------------------------------------------- /src/scss/colorview.scss: -------------------------------------------------------------------------------- 1 | /* codemirror colorview */ 2 | 3 | .codemirror-colorview { 4 | border : 1px solid #cecece; 5 | position: relative; 6 | display : inline-block; 7 | box-sizing : border-box; 8 | margin : 0px 2px; 9 | width : 10px; 10 | height : 10px; 11 | cursor: pointer; 12 | vertical-align: middle; 13 | @include transparent-background(); 14 | 15 | .codemirror-colorview-background { 16 | content: ""; 17 | position: absolute; 18 | left:0px; 19 | right:0px; 20 | bottom:0px; 21 | top:0px; 22 | } 23 | 24 | &:hover { 25 | border-color: #494949; 26 | } 27 | } 28 | 29 | 30 | -------------------------------------------------------------------------------- /src/scss/component/button.scss: -------------------------------------------------------------------------------- 1 | .arrow-button { 2 | position: relative; 3 | width: 10px; 4 | height: 12px; 5 | padding: 0px; 6 | background-color: transparent; 7 | 8 | &:before { 9 | content: ""; 10 | display:inline-block; 11 | position:absolute; 12 | left:0px; 13 | right:0px; 14 | top:0px; 15 | height:50%; 16 | @include arrow_top(3px, black); 17 | margin: 2px; 18 | box-sizing:border-box; 19 | } 20 | 21 | &:after { 22 | content: ""; 23 | display:inline-block; 24 | position:absolute; 25 | left:0px; 26 | right:0px; 27 | bottom:0px; 28 | top:50%; 29 | @include arrow_bottom(3px, black); 30 | margin: 2px; 31 | box-sizing:border-box; 32 | } 33 | } -------------------------------------------------------------------------------- /src/scss/component/colorsets-contextmenu.scss: -------------------------------------------------------------------------------- 1 | 2 | .colorsets-contextmenu { 3 | position:fixed; 4 | padding-top:4px; 5 | padding-bottom:4px; 6 | border-radius: 6px; 7 | background-color: #ececec; 8 | border: 1px solid rgba(204, 204, 204, 1); 9 | display: none; 10 | list-style: none; 11 | font-size: 13px; 12 | padding-left: 0px; 13 | padding-right: 0px; 14 | &.show { 15 | display:inline-block; 16 | } 17 | 18 | .menu-item { 19 | padding: 2px 20px; 20 | cursor: default; 21 | 22 | &:hover { 23 | background-color: #5ea3fb; 24 | color: white; 25 | } 26 | } 27 | 28 | &.small { 29 | .menu-item.small-hide { 30 | display: none; 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/scss/component/colorsets.scss: -------------------------------------------------------------------------------- 1 | 2 | .colorsets { 3 | border-top: 1px solid #e2e2e2; 4 | 5 | > .menu { 6 | float: right; 7 | padding: 10px 5px; 8 | padding-right: 15px; 9 | 10 | button { 11 | border:0px; 12 | font-size: 14px; 13 | font-weight: 300; 14 | font-family: serif, sans-serif; 15 | outline:none; 16 | cursor: pointer; 17 | } 18 | } 19 | 20 | > .color-list { 21 | margin-right: 30px; 22 | display: block; 23 | padding: 12px 0px 0px 12px; 24 | box-sizing:border-box; 25 | line-height: 0; 26 | 27 | .color-item { 28 | width: 13px; 29 | height: 13px; 30 | border-radius:2px; 31 | display:inline-block; 32 | margin-right:12px; 33 | margin-bottom:12px; 34 | position:relative; 35 | background-size: contain; 36 | overflow:hidden; 37 | box-sizing:border-box; 38 | cursor: pointer; 39 | vertical-align: middle; 40 | 41 | &:hover { 42 | transform: scale(1.2); 43 | } 44 | 45 | .empty { 46 | position: absolute; 47 | left:0px; 48 | top:0px; 49 | @include transparent-background(); 50 | width: 100%; 51 | height: 100%; 52 | padding: 0px; 53 | margin: 0px; 54 | pointer-events: none; 55 | } 56 | 57 | .color-view { 58 | position: absolute; 59 | left:0px; 60 | top:0px; 61 | width: 100%; 62 | height: 100%; 63 | padding:0px; 64 | margin:0px; 65 | pointer-events: none; 66 | border: 1px solid rgba(0, 0, 0, 0.1); 67 | box-sizing: border-box; 68 | } 69 | } 70 | 71 | .add-color-item { 72 | width: 13px; 73 | height: 13px; 74 | display:inline-block; 75 | margin-right:12px; 76 | margin-bottom:12px; 77 | cursor: pointer; 78 | line-height: 1; 79 | text-align: center; 80 | font-size: 16px; 81 | font-weight: 400; 82 | font-family: serif,sans-serif; 83 | color: rgb(142, 142, 142); 84 | vertical-align: middle; 85 | } 86 | } 87 | 88 | 89 | } -------------------------------------------------------------------------------- /src/scss/component/control.scss: -------------------------------------------------------------------------------- 1 | .control { 2 | position: relative; 3 | padding: 10px 0px 10px 0px; 4 | user-select: none; 5 | 6 | &.has-eyedropper { 7 | padding-left: 30px; 8 | 9 | .el-cp-color-control__left { 10 | position: absolute; 11 | left: 12px; 12 | top: 20px; 13 | width: 30px; 14 | height: 30px; 15 | border-radius: 50%; 16 | box-sizing: border-box; 17 | } 18 | 19 | > .color, > .empty { 20 | left: 45px; 21 | } 22 | } 23 | 24 | 25 | > .color, > .empty { 26 | position: absolute; 27 | left: 12px; 28 | top: 14px; 29 | width: 30px; 30 | height: 30px; 31 | border-radius: 50%; 32 | box-sizing: border-box; 33 | } 34 | 35 | > .color { 36 | border: 1px solid rgba(0, 0, 0, 0.1); 37 | } 38 | 39 | > .hue { 40 | position: relative; 41 | padding: 6px 16px; 42 | margin: 0px 0px 0px 42px; 43 | box-sizing: border-box; 44 | cursor: pointer; 45 | 46 | > .hue-container { 47 | position: relative; 48 | width: 100%; 49 | height: 10px; 50 | border-radius: 3px; 51 | } 52 | } 53 | 54 | 55 | > .opacity { 56 | position: relative; 57 | padding: 3px 16px; 58 | margin: 0px 0px 0px 42px; 59 | box-sizing: border-box; 60 | cursor: pointer; 61 | 62 | > .opacity-container { 63 | position: relative; 64 | width: 100%; 65 | height: 10px; 66 | border-radius: 3px; 67 | } 68 | } 69 | 70 | .drag-bar, .drag-bar2 { 71 | position: absolute; 72 | cursor: pointer; 73 | top: 50%; 74 | left: 0px; 75 | transform: translateX(-50%) translateY(-50%); 76 | width: 12px; 77 | height: 12px; 78 | border-radius: 50%; 79 | } 80 | 81 | > .hue > .hue-container { 82 | background: linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 83 | } 84 | 85 | > .opacity > .opacity-container { 86 | @include transparent-background(); 87 | 88 | > .color-bar { 89 | position:absolute; 90 | display:block; 91 | content:""; 92 | left:0px; 93 | right:0px; 94 | bottom:0px; 95 | top:0px; 96 | } 97 | } 98 | 99 | > .empty { 100 | @include transparent-background(); 101 | } 102 | 103 | .drag-bar, 104 | .drag-bar2 { 105 | border: 1px solid rgba(0, 0, 0, 0.05); 106 | box-shadow: 2px 2px 2px 0px rgba(0, 0, 0, 0.2); 107 | background-color: #fefefe; 108 | 109 | } 110 | 111 | } 112 | 113 | -------------------------------------------------------------------------------- /src/scss/component/information.scss: -------------------------------------------------------------------------------- 1 | .information { 2 | /*border-top: 1px solid #e8e8e8;*/ 3 | position: relative; 4 | box-sizing: padding-box; 5 | 6 | > input { 7 | position: absolute; 8 | font-size: 10px; 9 | height: 20px; 10 | bottom: 20px; 11 | padding: 0 0 0 2px; 12 | box-sizing: border-box; 13 | user-select: text; 14 | 15 | &[type=number] { 16 | appearance: none; 17 | } 18 | 19 | &[type=number]::-webkit-inner-spin-button, 20 | &[type=number]::-webkit-outer-spin-button 21 | { 22 | appearance: none; 23 | margin: 0; 24 | } 25 | } 26 | 27 | &.hex > .information-item.hex { 28 | display: flex; 29 | } 30 | 31 | &.rgb > .information-item.rgb { 32 | display: flex; 33 | } 34 | 35 | &.hsl > .information-item.hsl { 36 | display: flex; 37 | } 38 | 39 | > .information-item { 40 | display:none; 41 | position: relative; 42 | padding: 0px 5px; 43 | padding-left: 9px; 44 | box-sizing: border-box; 45 | margin-right:40px; 46 | 47 | > .input-field { 48 | display:block; 49 | flex:1; 50 | padding: 3px; 51 | box-sizing: border-box; 52 | position: relative; 53 | 54 | > .title { 55 | text-align:center; 56 | font-size:12px; 57 | color:#a9a9a9; 58 | padding-top:2px; 59 | cursor: pointer; 60 | user-select: none; 61 | } 62 | 63 | input { 64 | text-align: center; 65 | width:100%; 66 | padding:3px; 67 | height: 21px; 68 | font-size:11px; 69 | color: #333; 70 | box-sizing: border-box; 71 | user-select: text; 72 | border: 1px solid #cbcbcb; 73 | border-radius:2px; 74 | 75 | &[type=number] { 76 | appearance: none; 77 | } 78 | 79 | &[type=number]::-webkit-inner-spin-button, 80 | &[type=number]::-webkit-outer-spin-button 81 | { 82 | appearance: none; 83 | margin: 0; 84 | } 85 | } 86 | 87 | &.hsl-l, 88 | &.hsl-s { 89 | 90 | input[type=number] { 91 | padding-left: 1px; 92 | padding-right: 10px; 93 | 94 | } 95 | 96 | } 97 | 98 | .postfix { 99 | display:inline-block; 100 | position: absolute; 101 | right:3px; 102 | top:2px; 103 | height: 21px; 104 | line-height: 2; 105 | padding: 2px; 106 | box-sizing: border-box; 107 | text-align:center; 108 | font-size: 11px; 109 | } 110 | } 111 | } 112 | 113 | > .information-change { 114 | position:absolute; 115 | display:block; 116 | width:40px; 117 | top:0px; 118 | right:0px; 119 | bottom:0px; 120 | text-align: center; 121 | box-sizing: border-box; 122 | padding-top:5px; 123 | 124 | > .format-change-button { 125 | box-sizing: border-box; 126 | background:transparent; 127 | border:0px; 128 | cursor:pointer; 129 | outline:none; 130 | } 131 | } 132 | 133 | > .title { 134 | color: #a3a3a3; 135 | } 136 | 137 | > .input { 138 | color: #333; 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /src/scss/component/palette.scss: -------------------------------------------------------------------------------- 1 | 2 | 3 | .color { 4 | position: relative; 5 | height: 120px; 6 | overflow: hidden; 7 | cursor: pointer; 8 | 9 | > .saturation { 10 | position: relative; 11 | width: 100%; 12 | height: 100%; 13 | 14 | > .value { 15 | position: relative; 16 | width: 100%; 17 | height: 100%; 18 | 19 | > .drag-pointer { 20 | position: absolute; 21 | width: 10px; 22 | height: 10px; 23 | border-radius: 50%; 24 | transform: translateX(-50%) translateY(-50%); 25 | } 26 | } 27 | 28 | } 29 | 30 | > .saturation { 31 | background-color: rgba(204, 154, 129, 0); 32 | background-image: linear-gradient(to right, #FFF, rgba(204, 154, 129, 0)); 33 | background-repeat: repeat-x; 34 | 35 | > .value { 36 | background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0)); 37 | 38 | > .drag-pointer { 39 | border: 1px solid #fff; 40 | box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.05); 41 | } 42 | } 43 | } 44 | 45 | } -------------------------------------------------------------------------------- /src/scss/index.scss: -------------------------------------------------------------------------------- 1 | @import './mixins'; 2 | 3 | @import './colorview'; 4 | @import './colorpicker'; 5 | 6 | 7 | -------------------------------------------------------------------------------- /src/scss/mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin transparent-background () { 2 | background: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAJElEQVQYV2NctWrVfwYkEBYWxojMZ6SDAmT7QGx0K1EcRBsFAADeG/3M/HteAAAAAElFTkSuQmCC") repeat; 3 | } 4 | 5 | @mixin arrow_top ($pixel, $color) { 6 | width: 0; 7 | height: 0; 8 | border-left: $pixel solid transparent; 9 | border-right: $pixel solid transparent; 10 | border-bottom: $pixel solid $color; 11 | pointer-events: none; 12 | } 13 | 14 | @mixin arrow_bottom ($pixel, $color) { 15 | width: 0; 16 | height: 0; 17 | border-left: $pixel solid transparent; 18 | border-right: $pixel solid transparent; 19 | border-top: $pixel solid $color; 20 | pointer-events: none; 21 | } -------------------------------------------------------------------------------- /src/scss/themes/box.scss: -------------------------------------------------------------------------------- 1 | &.box { 2 | width: 420px; 3 | border-radius: 10px; 4 | .colorpicker-body { 5 | display: grid; 6 | padding: 10px 20px 10px 10px; 7 | grid-template-columns: 200px 1fr; 8 | column-gap: 10px; 9 | grid-template-rows: auto; 10 | 11 | > .color { 12 | height: 100%; 13 | border-radius: 8px; 14 | overflow: hidden; 15 | } 16 | } 17 | 18 | .control { 19 | padding: 0px !important; 20 | 21 | > * { 22 | vertical-align: middle; 23 | } 24 | 25 | .color-info { 26 | position: relative; 27 | height: 30px; 28 | width: 30px; 29 | display: inline-block; 30 | 31 | > .color, > .empty { 32 | position: absolute; 33 | width: 100%; 34 | height: 100%; 35 | border-radius: 50%; 36 | box-sizing: border-box; 37 | } 38 | 39 | > .color { 40 | border: 1px solid rgba(0, 0, 0, 0.1); 41 | } 42 | 43 | } 44 | 45 | > .color, > .empty { 46 | top: 4px; 47 | } 48 | 49 | &.has-eyedropper { 50 | padding-left: 30px; 51 | 52 | .el-cp-color-control__left { 53 | display: inline-block; 54 | width: 30px; 55 | height: 30px; 56 | position: relative; 57 | top: auto; 58 | left: auto; 59 | } 60 | } 61 | 62 | .hue, .opacity { 63 | padding-left: 0px !important; 64 | margin-left: 0px !important; 65 | padding-right: 0px !important; 66 | } 67 | 68 | } 69 | 70 | 71 | .value { 72 | position: relative; 73 | // padding: 6px 16px; 74 | // margin: 0px 0px 0px 42px; 75 | box-sizing: border-box; 76 | cursor: pointer; 77 | 78 | > .value-container { 79 | position: relative; 80 | width: 100%; 81 | height: 10px; 82 | border-radius: 3px; 83 | background-image: linear-gradient(to right, #000000 0%, rgba(255, 255, 255, 0) 100%); 84 | box-sizing: border-box; 85 | 86 | .drag-bar { 87 | position: absolute; 88 | cursor: pointer; 89 | top: 50%; 90 | left: 0px; 91 | transform: translateX(-50%) translateY(-50%); 92 | width: 12px; 93 | height: 12px; 94 | border-radius: 50%; 95 | } 96 | 97 | } 98 | } 99 | 100 | .information { 101 | margin-top: 6px; 102 | .information-change { 103 | display: none; 104 | } 105 | 106 | > .information-item { 107 | margin: 0px !important; 108 | padding: 0px !important; 109 | } 110 | } 111 | 112 | .colorsets { 113 | border: 0px; 114 | position: relative; 115 | 116 | .color-list { 117 | padding: 0px !important; 118 | margin-right: 0px !important; 119 | 120 | .current-color-sets { 121 | .color-item { 122 | width: 20px; 123 | height: 20px; 124 | margin-right: 4px !important; 125 | margin-bottom: 4px !important; 126 | } 127 | } 128 | } 129 | 130 | .menu { 131 | float: none; 132 | position: absolute; 133 | right: -20px; 134 | top: -15px; 135 | } 136 | } 137 | 138 | .color-chooser .color-chooser-container { 139 | top: 0px; 140 | left: 200px; 141 | } 142 | 143 | } -------------------------------------------------------------------------------- /src/scss/themes/macos.scss: -------------------------------------------------------------------------------- 1 | &.macos { 2 | .colorpicker-body { 3 | .wheel { 4 | width: 224px; 5 | height: 224px; 6 | position: relative; 7 | box-sizing: border-box; 8 | 9 | .wheel-canvas { 10 | width: 214px; 11 | height: 214px; 12 | border-radius: 50%; 13 | position: absolute; 14 | left:5px; 15 | top:5px; 16 | } 17 | 18 | .drag-pointer { 19 | display:inline-block; 20 | position: absolute; 21 | width: 10px; 22 | height: 10px; 23 | left:50%; 24 | top:50%; 25 | border:1px solid white; 26 | border-radius: 50%; 27 | transform: translateX(-50%) translateY(-50%); 28 | z-index:2; 29 | } 30 | } 31 | 32 | } 33 | 34 | .control { 35 | padding-top: 0px; 36 | 37 | > .color, > .empty { 38 | top: 4px; 39 | } 40 | 41 | &.has-eyedropper { 42 | padding-left: 30px; 43 | 44 | .el-cp-color-control__left { 45 | top: 9px; 46 | } 47 | } 48 | 49 | } 50 | 51 | 52 | .value { 53 | position: relative; 54 | padding: 6px 16px; 55 | margin: 0px 0px 0px 42px; 56 | box-sizing: border-box; 57 | cursor: pointer; 58 | 59 | > .value-container { 60 | position: relative; 61 | width: 100%; 62 | height: 10px; 63 | border-radius: 3px; 64 | background-image: linear-gradient(to right, #000000 0%, rgba(255, 255, 255, 0) 100%); 65 | box-sizing: border-box; 66 | 67 | .drag-bar { 68 | position: absolute; 69 | cursor: pointer; 70 | top: 50%; 71 | left: 0px; 72 | transform: translateX(-50%) translateY(-50%); 73 | width: 12px; 74 | height: 12px; 75 | border-radius: 50%; 76 | } 77 | 78 | } 79 | } 80 | } -------------------------------------------------------------------------------- /src/scss/themes/mini-vertical.scss: -------------------------------------------------------------------------------- 1 | &.mini-vertical { 2 | width: 180px; 3 | display: inline-block; 4 | 5 | .color { 6 | display:inline-block; 7 | width: 140px; 8 | height: 160px; 9 | vertical-align: middle; 10 | } 11 | 12 | .control { 13 | height: 160px; 14 | padding: 0px; 15 | vertical-align: middle; 16 | display:inline-block; 17 | 18 | .hue, .opacity { 19 | margin: 0px; 20 | padding:0px; 21 | width: 20px; 22 | display:inline-block; 23 | vertical-align: middle; 24 | height: 100%; 25 | position: relative; 26 | } 27 | 28 | .hue > .hue-container { 29 | border-radius:0px; 30 | overflow:hidden; 31 | height: 100%; 32 | background: linear-gradient(to top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 33 | } 34 | 35 | 36 | .opacity > .opacity-container { 37 | border-radius: 0px; 38 | overflow: hidden; 39 | height: 100%; 40 | width: 20px; 41 | } 42 | 43 | 44 | .drag-bar, .drag-bar2 { 45 | border:0px; 46 | background-color: transparent; 47 | height:2px; 48 | width:100%; 49 | box-sizing: border-box; 50 | box-shadow: none; 51 | transform: none; 52 | 53 | &.last { 54 | &:before, &:after { 55 | top: 2px; 56 | } 57 | } 58 | 59 | &.first { 60 | &:before, &:after { 61 | top: -1px; 62 | } 63 | } 64 | 65 | &:before { 66 | content: ""; 67 | position: absolute; 68 | left: 0px; 69 | top: 2px; 70 | width: 0; 71 | height: 0; 72 | transform: translateY(-50%); 73 | border-top: 4px solid transparent; 74 | border-bottom: 4px solid transparent; 75 | border-left: 4px solid black; 76 | } 77 | 78 | &:after { 79 | content: ""; 80 | position: absolute; 81 | top: 2px; 82 | right: 0px; 83 | width: 0; 84 | height: 0; 85 | transform: translateY(-50%); 86 | border-top: 4px solid transparent; 87 | border-bottom: 4px solid transparent; 88 | border-right: 4px solid black; 89 | } 90 | } 91 | 92 | } 93 | 94 | } -------------------------------------------------------------------------------- /src/scss/themes/mini.scss: -------------------------------------------------------------------------------- 1 | &.mini { 2 | width: 180px; 3 | display: inline-block; 4 | 5 | .control { 6 | padding: 0px; 7 | 8 | 9 | .hue, .opacity { 10 | margin: 0px; 11 | padding:0px; 12 | } 13 | 14 | .hue > .hue-container { 15 | border-radius:0px; 16 | overflow:hidden; 17 | height: 20px; 18 | } 19 | 20 | .opacity > .opacity-container { 21 | border-radius: 0px; 22 | overflow: hidden; 23 | height: 20px; 24 | } 25 | 26 | 27 | .drag-bar, .drag-bar2 { 28 | border:0px; 29 | background-color: transparent; 30 | height:100%; 31 | width:5px; 32 | box-sizing: border-box; 33 | box-shadow: none; 34 | 35 | &.last { 36 | &:before, &after { 37 | left: 1px; 38 | } 39 | } 40 | 41 | &.first { 42 | &:before, &:after { 43 | left: 3px; 44 | } 45 | } 46 | 47 | &:before { 48 | content: ""; 49 | position: absolute; 50 | left: 2px; 51 | top: 0px; 52 | width: 0; 53 | height: 0; 54 | transform: translateX(-50%); 55 | border-left: 4px solid transparent; 56 | border-right: 4px solid transparent; 57 | border-top: 4px solid black; 58 | } 59 | 60 | &:after { 61 | content: ""; 62 | position: absolute; 63 | left: 2px; 64 | bottom: 0px; 65 | width: 0; 66 | height: 0; 67 | transform: translateX(-50%); 68 | border-left: 4px solid transparent; 69 | border-right: 4px solid transparent; 70 | border-bottom: 4px solid black; 71 | } 72 | } 73 | 74 | } 75 | 76 | } -------------------------------------------------------------------------------- /src/scss/themes/palette.scss: -------------------------------------------------------------------------------- 1 | &.palette { 2 | border-radius: 3px; 3 | box-shadow: none; 4 | 5 | > .colorpicker-body { 6 | 7 | > .color { 8 | display: none; 9 | } 10 | 11 | > .control { 12 | display: none; 13 | } 14 | 15 | > .information { 16 | display: none; 17 | } 18 | 19 | > .colorsets { 20 | box-sizing: border-box; 21 | border-top:0px; 22 | 23 | > .color-list { 24 | .color-item { 25 | width: 15px; 26 | height: 15px; 27 | margin-right: 10px; 28 | margin-bottom: 10px; 29 | } 30 | } 31 | } 32 | 33 | > .color-chooser { 34 | display: none; 35 | box-sizing: border-box; 36 | &.open { 37 | display: block; 38 | top:-1px; 39 | left:-1px; 40 | right:-1px; 41 | bottom: auto; 42 | border-radius: 3px; 43 | border: 1px solid #d8d8d8; 44 | box-shadow: 0 0px 10px 2px rgba(0, 0, 0, 0.12); 45 | .color-chooser-container { 46 | position: relative; 47 | top: auto; 48 | left: auto; 49 | right: auto; 50 | bottom: auto; 51 | background-color: white; 52 | box-sizing: border-box; 53 | border-radius: 2px; 54 | 55 | .colorsets-item-header { 56 | position: relative; 57 | left:auto; 58 | top:auto; 59 | right:auto; 60 | bottom:auto; 61 | border-top-left-radius: 3px; 62 | border-top-right-radius: 3px; 63 | } 64 | 65 | .colorsets-list { 66 | position: relative; 67 | top: auto; 68 | left: auto; 69 | right: auto; 70 | bottom: auto; 71 | overflow: auto; 72 | 73 | .colorsets-item:last-child { 74 | border-bottom-left-radius: 3px; 75 | border-bottom-right-radius: 3px; 76 | } 77 | } 78 | } 79 | } 80 | } 81 | 82 | 83 | } 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/scss/themes/ring.scss: -------------------------------------------------------------------------------- 1 | &.ring { 2 | .colorpicker-body { 3 | 4 | > .color { 5 | position: absolute; 6 | width: 120px; 7 | height: 120px; 8 | left: 52px; 9 | top: 52px; 10 | } 11 | 12 | .wheel { 13 | width: 224px; 14 | height: 224px; 15 | position: relative; 16 | box-sizing: border-box; 17 | 18 | .wheel-canvas { 19 | width: 214px; 20 | height: 214px; 21 | border-radius: 50%; 22 | position: absolute; 23 | left:5px; 24 | top:5px; 25 | } 26 | 27 | .drag-pointer { 28 | display:inline-block; 29 | position: absolute; 30 | width: 10px; 31 | height: 10px; 32 | left:50%; 33 | top:50%; 34 | border:1px solid white; 35 | border-radius: 50%; 36 | transform: translateX(-50%) translateY(-50%); 37 | z-index:2; 38 | } 39 | } 40 | 41 | } 42 | 43 | .control { 44 | padding-top: 0px; 45 | 46 | .value { 47 | display: none; 48 | } 49 | 50 | > .color, > .empty { 51 | top: -17px; 52 | width: 30px; 53 | height: 30px; 54 | border-radius: 2px; 55 | } 56 | 57 | 58 | &.has-eyedropper { 59 | padding-left: 30px; 60 | padding-top: 10px; 61 | 62 | > .color, > .empty { 63 | top: -2px; 64 | } 65 | 66 | .el-cp-color-control__left { 67 | top: 4px; 68 | } 69 | } 70 | } 71 | } -------------------------------------------------------------------------------- /src/scss/themes/vscode.scss: -------------------------------------------------------------------------------- 1 | &.vscode { 2 | width: 336px; 3 | display: inline-block; 4 | background-color: #333; 5 | border: 1px solid #ececec; 6 | box-sizing: border-box; 7 | border-radius: 0px; 8 | 9 | .colorpicker-body { 10 | border-radius: 0px; 11 | display: inline-block; 12 | 13 | .color-view { 14 | height: 34px; 15 | 16 | &.has-eyedropper { 17 | display: flex; 18 | .color-view-container { 19 | width: 254px; 20 | display: inline-block; 21 | } 22 | 23 | 24 | .el-cp-color-control__left { 25 | float: right; 26 | width: 80px; 27 | text-align: center; 28 | padding: 6px 0px; 29 | 30 | button { 31 | display: inline-block; 32 | 33 | svg { 34 | path { 35 | fill: white; 36 | } 37 | } 38 | } 39 | } 40 | } 41 | 42 | .color-view-container { 43 | line-height: 34px; 44 | font-size: 14px; 45 | text-align: center; 46 | width: 100%; 47 | height: 100%; 48 | cursor: pointer; 49 | user-select: none; 50 | text-shadow: 0 0 3px rgb(83, 83, 83); 51 | @include transparent-background(); 52 | 53 | .preview { 54 | display: block; 55 | height: 100%; 56 | } 57 | } 58 | } 59 | 60 | .color-tool { 61 | padding: 8px; 62 | } 63 | } 64 | 65 | .color { 66 | display:inline-block; 67 | width: 240px; 68 | height: 160px; 69 | vertical-align: middle; 70 | } 71 | 72 | .control { 73 | height: 160px; 74 | vertical-align: middle; 75 | display:inline-block; 76 | padding: 0px 0px 0px 4px; 77 | 78 | .hue, .opacity { 79 | margin: 0px; 80 | padding:0px; 81 | width: 30px; 82 | display:inline-block; 83 | vertical-align: middle; 84 | height: 100%; 85 | position: relative; 86 | } 87 | 88 | 89 | .hue { 90 | padding-left: 5px; 91 | width: 35px; 92 | } 93 | 94 | .hue > .hue-container { 95 | border-radius:0px; 96 | height: 100%; 97 | background: linear-gradient(to top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 98 | } 99 | 100 | 101 | .opacity > .opacity-container { 102 | border-radius: 0px; 103 | height: 100%; 104 | width: 30px; 105 | } 106 | 107 | 108 | .drag-bar, .drag-bar2 { 109 | background-color: transparent; 110 | height:5px; 111 | width:33px; 112 | box-sizing: border-box; 113 | box-shadow: none; 114 | transform: translateY(-50%) translateX(-2px); 115 | border: 1px solid rgba(255, 255, 255, 1); 116 | border-radius: 0px; 117 | box-shadow: 0 0 2px 0 rgba(0, 0, 0, 1), inset 0 0 0 0 rgba(0, 0, 0, 1); 118 | 119 | 120 | } 121 | 122 | } 123 | 124 | } -------------------------------------------------------------------------------- /src/scss/themes/xd.scss: -------------------------------------------------------------------------------- 1 | &.xd { 2 | display: inline-block; 3 | // padding: 12px; 4 | padding-top: 12px; 5 | width: 245px; 6 | 7 | .color { 8 | display:inline-block; 9 | margin-left: 12px; 10 | margin-bottom: 12px; 11 | width: 170px; 12 | height: 170px; 13 | vertical-align: middle; 14 | border-radius: 3px; 15 | overflow: hidden; 16 | box-sizing: border-box; 17 | border: 1px solid #cecece; 18 | 19 | > .saturation { 20 | > .value { 21 | > .drag-pointer { 22 | border: 2px solid white; 23 | width: 7px; 24 | height: 7px; 25 | box-shadow: 0 0 1px 0px rgba(0, 0, 0, 1), inset 0 0 1px 0px rgba(0, 0, 0, 1); 26 | } 27 | } 28 | } 29 | 30 | } 31 | 32 | .control { 33 | height: 170px; 34 | padding: 0px; 35 | vertical-align: middle; 36 | display:inline-block; 37 | margin-right: 12px; 38 | margin-bottom: 12px; 39 | 40 | .hue, .opacity { 41 | margin: 0px; 42 | padding:0px; 43 | width: 13px; 44 | display:inline-block; 45 | vertical-align: middle; 46 | height: 100%; 47 | position: relative; 48 | overflow: hidden; 49 | border-radius: 3px; 50 | margin-left: 8px; 51 | } 52 | 53 | .hue > .hue-container { 54 | border-radius:0px; 55 | overflow:hidden; 56 | height: 100%; 57 | background: linear-gradient(to top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 58 | } 59 | 60 | 61 | .opacity > .opacity-container { 62 | border-radius: 0px; 63 | overflow: hidden; 64 | height: 100%; 65 | } 66 | 67 | 68 | .drag-bar, .drag-bar2 { 69 | border:0px; 70 | background-color: transparent; 71 | border: 2px solid white; 72 | box-shadow: 0 0 1px 0px rgba(0, 0, 0, 1), inset 0 0 1px 0px rgba(0, 0, 0, 1); 73 | width: 10px; 74 | height: 10px; 75 | box-sizing: border-box; 76 | transform: none; 77 | overflow: hidden; 78 | left: 50%; 79 | transform: translateX(-50%) translateY(-50%); 80 | } 81 | 82 | } 83 | 84 | .information { 85 | margin-top: 5px; 86 | } 87 | 88 | } -------------------------------------------------------------------------------- /src/util/Blender.js: -------------------------------------------------------------------------------- 1 | import separable from './blend/separable' 2 | import nonseparable from './blend/non-separable' 3 | import composite from './blend/composite' 4 | 5 | function num(n) { 6 | if (n < 0) return 0; 7 | return n > 255 ? 255 : n; 8 | } 9 | 10 | function Blender (back, source, blendFunction, blendMode = 'normal', compositeOperation = 'source-over') { 11 | 12 | const compositeFunction = composite[compositeOperation]; 13 | 14 | return compositeFunction(back, blendFunction(back, source, blendMode)); 15 | 16 | } 17 | 18 | Object.keys(separable).forEach(mode => { 19 | Blender[mode] = function (back, source, compositeOperation = 'source-over') { 20 | return Blender(back, source, separable[mode],mode, compositeOperation) 21 | } 22 | }) 23 | Object.keys(nonseparable).forEach(mode => { 24 | Blender[mode] = function (back, source, compositeOperation = 'source-over') { 25 | return Blender(back, source, nonseparable[mode],mode, compositeOperation) 26 | } 27 | }) 28 | 29 | export default Blender -------------------------------------------------------------------------------- /src/util/Color.js: -------------------------------------------------------------------------------- 1 | import formatter from "./functions/formatter"; 2 | import math from './functions/math' 3 | import fromRGB from './functions/fromRGB' 4 | import fromCMYK from './functions/fromCMYK' 5 | import fromLAB from './functions/fromLAB' 6 | import fromHSV from './functions/fromHSV' 7 | import fromHSL from './functions/fromHSL' 8 | import fromYCrCb from './functions/fromYCrCb' 9 | import mixin from "./functions/mixin"; 10 | import parser from "./functions/parser"; 11 | import image from "./functions/image"; 12 | 13 | 14 | export default { 15 | ...formatter, 16 | ...math, 17 | ...mixin, 18 | ...parser, 19 | ...fromYCrCb, 20 | ...fromRGB, 21 | ...fromCMYK, 22 | ...fromHSV, 23 | ...fromHSL, 24 | ...fromLAB, 25 | ...image 26 | } 27 | 28 | -------------------------------------------------------------------------------- /src/util/Event.js: -------------------------------------------------------------------------------- 1 | export default { 2 | 3 | addEvent (dom, eventName, callback, options) { 4 | if (dom) { 5 | dom.addEventListener(eventName, callback, options); 6 | } 7 | }, 8 | 9 | removeEvent(dom, eventName, callback) { 10 | if (dom) { 11 | dom.removeEventListener(eventName, callback); 12 | } 13 | }, 14 | 15 | pos(e) { 16 | if (e.touches && e.touches[0]) { 17 | return e.touches[0]; 18 | } 19 | 20 | return e; 21 | }, 22 | 23 | posXY (e) { 24 | var pos = this.pos(e); 25 | return { 26 | x: pos.pageX, 27 | y: pos.pageY 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /src/util/GL.js: -------------------------------------------------------------------------------- 1 | import FilterFunctions from './gl/functions' 2 | 3 | import FilterList from './gl/index' 4 | 5 | export default { 6 | ...FilterList, 7 | ...FilterFunctions 8 | } 9 | -------------------------------------------------------------------------------- /src/util/HueColor.js: -------------------------------------------------------------------------------- 1 | import Color from './Color'; 2 | 3 | const hue_color = [ 4 | { rgb : '#ff0000', start : .0 }, 5 | { rgb : '#ffff00', start : .17 }, 6 | { rgb : '#00ff00', start : .33 }, 7 | { rgb : '#00ffff', start : .50 }, 8 | { rgb : '#0000ff', start : .67 }, 9 | { rgb : '#ff00ff', start : .83 }, 10 | { rgb : '#ff0000', start : 1 } 11 | ]; 12 | 13 | function checkHueColor(p) { 14 | var startColor, endColor; 15 | 16 | for(var i = 0; i < hue_color.length;i++) { 17 | if (hue_color[i].start >= p) { 18 | startColor = hue_color[i-1]; 19 | endColor = hue_color[i]; 20 | break; 21 | } 22 | } 23 | 24 | if (startColor && endColor) { 25 | return Color.interpolateRGB(startColor, endColor, (p - startColor.start)/(endColor.start - startColor.start)); 26 | } 27 | 28 | return hue_color[0].rgb; 29 | } 30 | 31 | 32 | function initHueColors () { 33 | for(var i = 0, len = hue_color.length; i < len; i++) { 34 | var hue = hue_color[i]; 35 | 36 | var obj = Color.parse(hue.rgb); 37 | 38 | hue.r = obj.r; 39 | hue.g = obj.g; 40 | hue.b = obj.b; 41 | } 42 | } 43 | 44 | initHueColors(); 45 | 46 | export default { 47 | colors : hue_color, 48 | checkHueColor 49 | }; -------------------------------------------------------------------------------- /src/util/ImageFilter.js: -------------------------------------------------------------------------------- 1 | // TODO: worker run 2 | import FilterFunctions from './filter/functions' 3 | 4 | import FilterList from './filter/index' 5 | 6 | export default { 7 | ...FilterList, 8 | ...FilterFunctions 9 | } 10 | -------------------------------------------------------------------------------- /src/util/State.js: -------------------------------------------------------------------------------- 1 | const DELEGATE_SPLIT = '.'; 2 | 3 | export default class State { 4 | constructor (masterObj, settingObj = {}) { 5 | 6 | this.masterObj = masterObj; 7 | this.settingObj = settingObj; 8 | } 9 | 10 | set (key, value, defaultValue = undefined) { 11 | this.settingObj[key] = value || defaultValue; 12 | } 13 | 14 | init (key, ...args) { 15 | 16 | if (!this.has(key)) { 17 | 18 | const arr = key.split(DELEGATE_SPLIT); 19 | 20 | const obj = this.masterObj.refs[arr[0]] || this.masterObj[arr[0]] || this.masterObj; 21 | const method = arr.pop(); 22 | 23 | if (obj[method]) { 24 | const value = obj[method].apply(obj, args); 25 | 26 | this.set(key, value); 27 | } 28 | 29 | } 30 | } 31 | 32 | get (key, defaultValue = '') { 33 | 34 | this.init(key, defaultValue); 35 | 36 | return this.settingObj[key] || defaultValue; 37 | } 38 | 39 | has (key) { 40 | return !!this.settingObj[key]; 41 | } 42 | } -------------------------------------------------------------------------------- /src/util/blend/composite.js: -------------------------------------------------------------------------------- 1 | const modes = { 2 | 'clear' : { 3 | alpha () { return 0; }, 4 | color () { return 0; } 5 | }, 6 | 'copy' : { 7 | alpha (Ab, As) { 8 | return As; 9 | }, 10 | color (Ab, As, Cb, Cs) { 11 | return As * Cs; 12 | } 13 | }, 14 | 'destination' : { 15 | alpha (Ab, As) { 16 | return Ab; 17 | }, 18 | color (Ab, As, Cb, Cs) { 19 | return Ab * Cb; 20 | } 21 | }, 22 | 'source-over' : { 23 | alpha (Ab, As) { 24 | return As + Ab * ( 1 - As); 25 | }, 26 | color (Ab, As, Cb, Cs) { 27 | return As * Cs + Ab * Cb * (1 - As); 28 | } 29 | }, 30 | 'destination-over' : { 31 | alpha (Ab, As) { 32 | return As * (1 - Ab) + Ab; 33 | }, 34 | color (Ab, As, Cb, Cs) { 35 | return As * Cs * (1 - Ab) + Ab * Cb; 36 | } 37 | }, 38 | 'source-in' : { 39 | alpha (Ab, As) { 40 | return As * Ab; 41 | }, 42 | color (Ab, As, Cb, Cs) { 43 | return As * Cs * Ab; 44 | } 45 | }, 46 | 'destination-in' : { 47 | alpha (Ab, As) { 48 | return As * Ab; 49 | }, 50 | color (Ab, As, Cb, Cs) { 51 | return As * Cb * Ab; 52 | } 53 | }, 54 | 'source-out' : { 55 | alpha (Ab, As) { 56 | return As * (1 - Ab); 57 | }, 58 | color (Ab, As, Cb, Cs) { 59 | return As * Cs * (1 - Ab); 60 | } 61 | }, 62 | 'destination-out' : { 63 | alpha (Ab, As) { 64 | return Ab * (1 - As); 65 | }, 66 | color (Ab, As, Cb, Cs) { 67 | return Ab * Cb * (1 - As); 68 | } 69 | }, 70 | 'source-atop' : { 71 | alpha (Ab, As) { 72 | return As * Ab + Ab * (1 - As); 73 | }, 74 | color (Ab, As, Cb, Cs) { 75 | return As * Cs * Ab + Ab * Cb * (1 - As); 76 | } 77 | }, 78 | 'destination-atop' : { 79 | alpha (Ab, As) { 80 | return As * (1 - Ab) + Ab * As; 81 | }, 82 | color (Ab, As, Cb, Cs) { 83 | return As * Cs * (1 - Ab) + Ab * Cb * As; 84 | } 85 | }, 86 | 'xor' : { 87 | alpha (Ab, As) { 88 | return As * (1 - Ab) + Ab * (1 - As); 89 | }, 90 | color (Ab, As, Cb, Cs) { 91 | return As * Cs * (1 - Ab) + Ab * Cb * (1 - As); 92 | } 93 | }, 94 | 'lighter' : { 95 | alpha (Ab, As) { 96 | return As + Ab 97 | }, 98 | color (Ab, As, Cb, Cs) { 99 | return As * Cs + Ab * Cb; 100 | } 101 | } 102 | 103 | 104 | 105 | 106 | } 107 | 108 | function composite (back, source, mode) { 109 | return { 110 | r : modes[mode].color(back.a, source.a, back.r / 255, source.r / 255) * 255, 111 | g : modes[mode].color(back.a, source.a, back.g / 255, source.g / 255) * 255, 112 | b : modes[mode].color(back.a, source.a, back.b / 255, source.b / 255) * 255, 113 | a : modes[mode].alpha(back.a, source.a) 114 | } 115 | } 116 | 117 | // alias 118 | Object.keys(modes).forEach(mode => { 119 | composite[mode] = function (back, source) { 120 | return composite(back, source, mode); 121 | } 122 | }) 123 | 124 | export default composite; -------------------------------------------------------------------------------- /src/util/blend/non-separable.js: -------------------------------------------------------------------------------- 1 | // refer to https://www.w3.org/TR/compositing-1 2 | 3 | var util = { 4 | lum ( color) { 5 | return 0.3 * color.r + 0.59 * color.g + 0.11 * color.b; 6 | }, 7 | 8 | clipColor(c) { 9 | const l = this.lum(c) 10 | const n = this.min(c) 11 | const x = this.max(c) 12 | 13 | let color = Object.assign({}, c); 14 | 15 | if(n < 0) { 16 | color.r = l + (((color.r - l) * l) / (l - n)) 17 | color.g = l + (((color.g - l) * l) / (l - n)) 18 | color.b = l + (((color.b - l) * l) / (l - n)) 19 | } 20 | 21 | 22 | if(x > 1) { 23 | color.r = l + (((color.r - l) * (1 - l)) / (x - l)) 24 | color.g = l + (((color.g - l) * (1 - l)) / (x - l)) 25 | color.b = l + (((color.b - l) * (1 - l)) / (x - l)) 26 | } 27 | 28 | return color; 29 | }, 30 | setLum(color, l) { 31 | const d = l - this.lum(color) 32 | const r = color.r + d; 33 | const g = color.g + d; 34 | const b = color.b + d; 35 | 36 | return this.clipColor({r, g, b}) 37 | }, 38 | 39 | sat (color) { 40 | return this.max(color) - this.min(color) 41 | }, 42 | 43 | max (color) { 44 | return Math.max(color.r, color.g, color.b); 45 | }, 46 | 47 | min (color) { 48 | return Math.min(color.r, color.g, color.b); 49 | }, 50 | 51 | mid (color) { 52 | return (color.r + color.g + color.b) - this.max(color) - this.min(color); 53 | }, 54 | 55 | setSat(color, s) { 56 | color.max = this.max(color); 57 | color.min = this.min(color); 58 | color.mid = this.mid(color); 59 | 60 | if(color.max > color.min) { 61 | color.mid = (((color.mid - color.min) * s) / (color.max - color.min)) 62 | color.max = s 63 | } else { 64 | color.mid = color.max = 0 65 | } 66 | 67 | color.min = 0 68 | 69 | return color; 70 | } 71 | } 72 | 73 | var modes = { 74 | /* nonseparable mode */ 75 | hue (back, source) { 76 | return util.setLum(util.setSat(source, util.sat(back)), util.lum(back)) 77 | }, 78 | 79 | saturation (back, source) { 80 | return util.setLum(util.setSat(back, util.sat(source)), util.lum(back)) 81 | }, 82 | 83 | color (back, source) { 84 | return util.setLum(source, util.lum(back)); 85 | }, 86 | 87 | luminosity (back, source) { 88 | return util.setLum(back, util.lum(source)) 89 | } 90 | 91 | } 92 | 93 | function recover (c) { 94 | c.r *= 255; 95 | c.g *= 255; 96 | c.b *= 255; 97 | return c; 98 | } 99 | 100 | function minify (c) { 101 | c.r /= 255; 102 | c.g /= 255; 103 | c.b /= 255; 104 | return c; 105 | } 106 | 107 | function nonseparable (back, source, mode) { 108 | return recover(modes[mode](minify(back), minify(source))); 109 | } 110 | 111 | // alias 112 | Object.keys(modes).forEach(mode => { 113 | nonseparable[mode] = function (back, source) { 114 | return nonseparable(back, source, mode); 115 | } 116 | }) 117 | 118 | export default nonseparable; -------------------------------------------------------------------------------- /src/util/blend/separable.js: -------------------------------------------------------------------------------- 1 | import { sep } from "path"; 2 | 3 | // refer to https://www.w3.org/TR/compositing-1 4 | var modes = { 5 | normal ( back, source) { 6 | return source; 7 | }, 8 | multiply (back, source) { 9 | return back * source ; 10 | }, 11 | screen (back, source) { 12 | return back + source -(back * source); 13 | }, 14 | overlay (back, source) { 15 | return this.hardlight(back, source) 16 | }, 17 | hardlight (back, source) { 18 | if(source <= 0.5) 19 | return this.multiply(back, 2 * source) 20 | else 21 | return this.screen(back, 2 * source - 1) 22 | }, 23 | diffuse (c) { 24 | if(c <= 0.25) 25 | return ((16 * c - 12) * c + 4) * c 26 | else 27 | return Math.sqrt(c) 28 | }, 29 | 30 | softlight (back, source) { 31 | if(source <= 0.5) 32 | return back - (1 - 2 * source) * back * (1 - back) 33 | else 34 | return back + (2 * source - 1) * (this.diffuse(back) - back) 35 | }, 36 | difference (back, source) { 37 | return Math.abs(back, source); 38 | }, 39 | exclusion (back, source) { 40 | return back + source - 2 * back * source 41 | }, 42 | darken (back, source) { 43 | return Math.min(back, source) 44 | }, 45 | lighten (back, source) { 46 | return Math.max(back, source) 47 | }, 48 | colordodge (back, source) { 49 | if(back == 0) return 0; 50 | else if(source == 1) return 1; 51 | else Math.min(1, back / (1 - source)) 52 | }, 53 | colorburn (back, source) { 54 | if(back == 1) return 1; 55 | else if(source == 0) return 0; 56 | else 1 - Math.min(1, (1 - back) / source) 57 | } 58 | } 59 | 60 | function separable (back, source, mode) { 61 | return { 62 | r : modes[mode](back.r / 255, source.r / 255) * 255, 63 | g : modes[mode](back.g / 255, source.g / 255) * 255, 64 | b : modes[mode](back.b / 255, source.b / 255) * 255, 65 | a : source.a 66 | } 67 | } 68 | 69 | // alias 70 | Object.keys(modes).forEach(mode => { 71 | separable[mode] = function (back, source) { 72 | return separable(back, source, mode); 73 | } 74 | }) 75 | 76 | export default separable; -------------------------------------------------------------------------------- /src/util/filter/image/crop.js: -------------------------------------------------------------------------------- 1 | import { createBitmap } from '../functions' 2 | 3 | export default function crop (startX = 0, startY = 0, width, height) { 4 | 5 | const newBitmap = createBitmap(width * height * 4, width, height) 6 | 7 | return function (bitmap, done, opt = {}) { 8 | for (var y = startY, realY = 0; y < height; y++, realY++) { 9 | for (var x = startX, realX = 0; x < width; x++, realX++) { 10 | newBitmap.pixels[realY * width * realX] = bitmap.pixels[y * width * x] 11 | } 12 | } 13 | 14 | done(newBitmap); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/util/filter/image/flipH.js: -------------------------------------------------------------------------------- 1 | import {swapColor} from '../functions' 2 | export default function flipH () { 3 | return function (bitmap, done, opt = {}) { 4 | 5 | const width = bitmap.width 6 | const height = bitmap.height 7 | const isCenter = width % 2 == 1 ? 1 : 0 8 | 9 | const halfWidth = isCenter ? Math.floor(width / 2) : width / 2 ; 10 | 11 | for (var y = 0; y < height; y++) { 12 | for (var x = 0; x < halfWidth; x++) { 13 | 14 | var startIndex = (y * width + x) << 2 15 | var endIndex = (y * width + (width -1 - x) ) << 2 16 | swapColor(bitmap.pixels, startIndex, endIndex) 17 | 18 | } 19 | } 20 | 21 | done(bitmap); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/util/filter/image/flipV.js: -------------------------------------------------------------------------------- 1 | import { 2 | swapColor 3 | } from '../functions' 4 | export default function flipV () { 5 | return function (bitmap, done, opt = {}) { 6 | 7 | const width = bitmap.width 8 | const height = bitmap.height 9 | const isCenter = height % 2 == 1 ? 1 : 0 10 | 11 | const halfHeight = isCenter ? Math.floor(height / 2) : height / 2 ; 12 | 13 | for (var y = 0; y < halfHeight; y++) { 14 | for (var x = 0; x < width; x++) { 15 | 16 | var startIndex = (y * width + x) << 2 17 | var endIndex = ((height -1 - y) * width + x ) << 2 18 | swapColor(bitmap.pixels, startIndex, endIndex) 19 | 20 | } 21 | } 22 | 23 | done(bitmap); 24 | } 25 | } -------------------------------------------------------------------------------- /src/util/filter/image/histogram.js: -------------------------------------------------------------------------------- 1 | import { pixel } from '../functions' 2 | 3 | export default function histogram (type = 'gray', points = []) { 4 | var $realPoints = [] 5 | 6 | for(var i = 0; i < points.length - 1; i++) { 7 | var sp = points[i] 8 | var ep = points[i+1] 9 | 10 | var distX = ep[0] - sp[0] 11 | var distY = ep[1] - sp[1] 12 | 13 | var rate = distY / distX 14 | 15 | for(var realIndex = 0, start = sp[0]; realIndex < distX; realIndex++, start++ ) { 16 | $realPoints[start] = sp[1] + realIndex * rate 17 | } 18 | } 19 | 20 | $realPoints[255] = 255 21 | 22 | if (type === 'red') { 23 | return pixel(() => { 24 | $r = $realPoints[$r]; 25 | }, { }, { $realPoints }) 26 | } else if (type === 'green') { 27 | return pixel(() => { 28 | $g = $realPoints[$g]; 29 | }, { }, { $realPoints }) 30 | } else if (type === 'blue') { 31 | return pixel(() => { 32 | $b = $realPoints[$b]; 33 | }, { }, { $realPoints }) 34 | } else { 35 | return pixel(() => { 36 | 37 | const l = Color.RGBtoYCrCb($r, $g, $b); 38 | const c = Color.YCrCbtoRGB(clamp($realPoints[clamp(l.y)]), l.cr, l.cb, 0) 39 | $r = c.r 40 | $g = c.g 41 | $b = c.b 42 | 43 | }, { }, { $realPoints }) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/util/filter/image/index.js: -------------------------------------------------------------------------------- 1 | import crop from './crop' 2 | import resize from './resize' 3 | import flipV from './flipV' 4 | import flipH from './flipH' 5 | import rotate from './rotate' 6 | import rotateDegree from './rotateDegree' 7 | import histogram from './histogram' 8 | 9 | export default { 10 | crop, 11 | resize, 12 | flipH, 13 | flipV, 14 | rotate, 15 | rotateDegree, 16 | histogram, 17 | 'rotate-degree' : rotateDegree 18 | } -------------------------------------------------------------------------------- /src/util/filter/image/resize.js: -------------------------------------------------------------------------------- 1 | import Canvas from '../../Canvas' 2 | // Image manupulate 3 | export default function resize (dstWidth, dstHeight) { 4 | return function (bitmap, done, opt = {}) { 5 | 6 | var c = Canvas.drawPixels(bitmap); 7 | var context = c.getContext('2d'); 8 | 9 | c.width = dstWidth; 10 | c.height = dstHeight; 11 | 12 | done({ 13 | pixels: new Uint8ClampedArray(context.getImageData(0, 0, dstWidth, dstHeight).data), 14 | width: dstWidth, 15 | height: dstHeight 16 | }) 17 | } 18 | } -------------------------------------------------------------------------------- /src/util/filter/image/rotate.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | packXY, 4 | createBitmap, 5 | fillPixelColor 6 | } from '../functions' 7 | 8 | import rotateDegree from './rotateDegree' 9 | 10 | export default function rotate (degree = 0) { 11 | degree = parseParamNumber(degree) 12 | degree = degree % 360 13 | return function (bitmap, done, opt = {}) { 14 | 15 | if (degree == 0) return bitmap 16 | 17 | if (degree == 90 || degree == 270) { 18 | var newBitmap = createBitmap(bitmap.pixels.length, bitmap.height, bitmap.width) 19 | } else if (degree == 180) { 20 | var newBitmap = createBitmap(bitmap.pixels.length, bitmap.width, bitmap.height) 21 | } else { 22 | return rotateDegree(degree)(bitmap, done, opt) 23 | } 24 | packXY((pixels, i, x, y) => { 25 | 26 | if (degree == 90) { 27 | var endIndex = (x * newBitmap.width + (newBitmap.width -1 - y) ) << 2 // << 2 is equals to (multiply)* 4 28 | } else if (degree == 270) { 29 | var endIndex = ( (newBitmap.height -1 -x) * newBitmap.width + y ) << 2 30 | } else if (degree == 180) { 31 | var endIndex = ((newBitmap.height -1 -y) * newBitmap.width + (newBitmap.width -1 -x)) << 2 32 | } 33 | 34 | fillPixelColor(newBitmap.pixels, endIndex, bitmap.pixels, i) 35 | })(bitmap, function () { 36 | done(newBitmap) 37 | }, opt) 38 | } 39 | } -------------------------------------------------------------------------------- /src/util/filter/image/rotateDegree.js: -------------------------------------------------------------------------------- 1 | import Matrix from '../../Matrix' 2 | import { 3 | createBitmap, 4 | packXY, 5 | fillPixelColor 6 | } from '../functions' 7 | 8 | export default function rotateDegree(angle, cx = 'center', cy = 'center') { 9 | // const r = F.radian(angle) 10 | 11 | return function (bitmap, done, opt = {}) { 12 | var newBitmap = createBitmap(bitmap.pixels.length, bitmap.width, bitmap.height) 13 | const width = bitmap.width 14 | const height = bitmap.height 15 | 16 | if (cx == 'center') { 17 | cx = Math.floor(width / 2); 18 | } 19 | 20 | if (cy == 'center') { 21 | cy = Math.floor(height/ 2); 22 | } 23 | 24 | const translateMatrix = Matrix.CONSTANT.translate(-cx, -cy) 25 | const translateMatrix2 = Matrix.CONSTANT.translate(cx, cy) 26 | const shear1Matrix = Matrix.CONSTANT.shear1(angle) 27 | const shear2Matrix = Matrix.CONSTANT.shear2(angle) 28 | 29 | packXY((pixels, i, x, y) => { 30 | // console.log(x, y, i) 31 | let arr = Matrix.multiply(translateMatrix, [x, y, 1]) 32 | 33 | arr = Matrix.multiply(shear1Matrix, arr).map(Math.round) 34 | arr = Matrix.multiply(shear2Matrix, arr).map(Math.round) 35 | arr = Matrix.multiply(shear1Matrix, arr).map(Math.round) 36 | arr = Matrix.multiply(translateMatrix2, arr) 37 | 38 | const [x1, y1] = arr 39 | 40 | if (x1 < 0) return; 41 | if (y1 < 0) return; 42 | if (x1 > width-1) return; 43 | if (y1 > height-1) return; 44 | 45 | var endIndex = (y1 * width + x1) << 2 // bit 2 shift is * 4 46 | 47 | fillPixelColor(pixels, endIndex, bitmap.pixels, i) 48 | 49 | })(newBitmap, function () { 50 | done(newBitmap) 51 | }, opt) 52 | } 53 | } -------------------------------------------------------------------------------- /src/util/filter/index.js: -------------------------------------------------------------------------------- 1 | import image from './image/index' 2 | import pixel from './pixel/index' 3 | import matrix from './matrix/index' 4 | import multi from './multi/index' 5 | 6 | export default { 7 | ...image, 8 | ...pixel, 9 | ...matrix, 10 | ...multi 11 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/blur.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution, 3 | parseParamNumber, 4 | createBlurMatrix 5 | } from '../functions' 6 | 7 | export default function (amount = 3, hasAlphaChannel = true) { 8 | 9 | amount = parseParamNumber(amount) 10 | 11 | return convolution(createBlurMatrix(amount)) 12 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/emboss.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution 4 | } from '../functions' 5 | /* 6 | * carve, mold, or stamp a design on (a surface) so that it stands out in relief. 7 | * 8 | * @param {Number} amount 0.0 .. 4.0 9 | */ 10 | export default function emboss (amount = 4) { 11 | amount = parseParamNumber(amount) 12 | return convolution([ 13 | amount * (-2.0), -amount, 0.0, 14 | -amount, 1.0, amount, 15 | 0.0, amount, amount * 2.0, 16 | ]); 17 | } 18 | -------------------------------------------------------------------------------- /src/util/filter/matrix/gaussian-blur-5x.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function gaussianBlur5x (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | const C = amount / 100; 10 | return convolution(weight([ 11 | 1, 4, 6, 4, 1, 12 | 4, 16, 24, 16, 4, 13 | 6, 24, 36, 24, 6, 14 | 4, 16, 24, 16, 4, 15 | 1, 4, 6, 4, 1 16 | ], (1/256) * C )); 17 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/gaussian-blur.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function gaussianBlur (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | const C = amount / 100; 10 | 11 | return convolution(weight([ 12 | 1, 2, 1, 13 | 2, 4, 2, 14 | 1, 2, 1 15 | ], (1/16) * C )); 16 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/grayscale2.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function grayscale2 (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | 0.3, 0.3, 0.3, 0, 0, 11 | 0.59, 0.59, 0.59, 0, 0, 12 | 0.11, 0.11, 0.11, 0, 0, 13 | 0, 0, 0, 0, 0, 14 | 0, 0, 0, 0, 0 15 | ], amount / 100)); 16 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/index.js: -------------------------------------------------------------------------------- 1 | import blur from './blur' 2 | import emboss from './emboss' 3 | import gaussianBlur from './gaussian-blur' 4 | import gaussianBlur5x from './gaussian-blur-5x' 5 | import grayscale2 from './grayscale2' 6 | import normal from './normal' 7 | import kirschHorizontal from './kirsch-horizontal' 8 | import kirschVertical from './kirsch-vertical' 9 | import laplacian from './laplacian' 10 | import laplacian5x from './laplacian-5x' 11 | import motionBlur from './motion-blur' 12 | import motionBlur2 from './motion-blur-2' 13 | import motionBlur3 from './motion-blur-3' 14 | import negative from './negative' 15 | import sepia2 from './sepia2' 16 | import sharpen from './sharpen' 17 | import sobelHorizontal from './sobel-horizontal' 18 | import sobelVertical from './sobel-vertical' 19 | import stackBlur from './stack-blur' 20 | import transparency from './transparency' 21 | import unsharpMasking from './unsharp-masking' 22 | 23 | 24 | export default { 25 | blur, 26 | emboss, 27 | gaussianBlur, 28 | 'gaussian-blur': gaussianBlur, 29 | gaussianBlur5x, 30 | 'gaussian-blur-5x': gaussianBlur5x, 31 | grayscale2, 32 | normal, 33 | kirschHorizontal, 34 | 'kirsch-horizontal': kirschHorizontal, 35 | kirschVertical, 36 | 'kirsch-vertical': kirschVertical, 37 | laplacian, 38 | laplacian5x, 39 | 'laplacian-5x': laplacian5x, 40 | motionBlur, 41 | 'motion-blur': motionBlur, 42 | motionBlur2, 43 | 'motion-blur-2': motionBlur2, 44 | motionBlur3, 45 | 'motion-blur-3': motionBlur3, 46 | negative, 47 | sepia2, 48 | sharpen, 49 | sobelHorizontal, 50 | 'sobel-horizontal': sobelHorizontal, 51 | sobelVertical, 52 | 'sobel-vertical': sobelVertical, 53 | stackBlur, 54 | 'stack-blur': stackBlur, 55 | transparency, 56 | unsharpMasking, 57 | 'unsharp-masking': unsharpMasking 58 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/kirsch-horizontal.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution 4 | } from '../functions' 5 | 6 | export default function kirschHorizontal (count = 1) { 7 | count = parseParamNumber(count) 8 | return convolution([ 9 | 5, 5, 5, 10 | -3, 0, -3, 11 | -3, -3, -3 12 | ]); 13 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/kirsch-vertical.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution 4 | } from '../functions' 5 | 6 | export default function kirschVertical (count = 1) { 7 | count = parseParamNumber(count) 8 | return convolution([ 9 | 5, -3, -3, 10 | 5, 0, -3, 11 | 5, -3, -3 12 | ]); 13 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/laplacian-5x.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function laplacian5x (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | -1, -1, -1, -1, -1, 11 | -1, -1, -1, -1, -1, 12 | -1, -1, 24, -1, -1, 13 | -1, -1, -1, -1, -1, 14 | -1, -1, -1, -1, -1 15 | ], amount / 100)); 16 | } 17 | -------------------------------------------------------------------------------- /src/util/filter/matrix/laplacian.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function laplacian (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | -1, -1, -1, 11 | -1, 8, -1, 12 | -1, -1, -1 13 | ], amount / 100)); 14 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/motion-blur-2.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution, 3 | weight 4 | } from '../functions' 5 | 6 | export default function motionBlur2 () { 7 | return convolution(weight([ 8 | 1, 0, 0, 0, 0, 0, 0, 0, 1, 9 | 0, 1, 0, 0, 0, 0, 0, 1, 0, 10 | 0, 0, 1, 0, 0, 0, 1, 0, 0, 11 | 0, 0, 0, 1, 0, 1, 0, 0, 0, 12 | 0, 0, 0, 0, 1, 0, 0, 0, 0, 13 | 0, 0, 0, 1, 0, 1, 0, 0, 0, 14 | 0, 0, 1, 0, 0, 0, 1, 0, 0, 15 | 0, 1, 0, 0, 0, 0, 0, 1, 0, 16 | 1, 0, 0, 0, 0, 0, 0, 0, 1, 17 | ], 1 / 9)); 18 | } 19 | -------------------------------------------------------------------------------- /src/util/filter/matrix/motion-blur-3.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution, 3 | weight 4 | } from '../functions' 5 | 6 | 7 | export default function motionBlur3 () { 8 | return convolution(weight([ 9 | 1, 0, 0, 0, 1, 0, 0, 0, 1, 10 | 0, 1, 0, 0, 1, 0, 0, 1, 0, 11 | 0, 0, 1, 0, 1, 0, 1, 0, 0, 12 | 0, 0, 0, 1, 1, 1, 0, 0, 0, 13 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 14 | 0, 0, 0, 1, 1, 1, 0, 0, 0, 15 | 0, 0, 1, 0, 1, 0, 1, 0, 0, 16 | 0, 1, 0, 0, 1, 0, 0, 1, 0, 17 | 1, 0, 0, 0, 1, 0, 0, 0, 1, 18 | ], 1 / 9)); 19 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/motion-blur.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution, 3 | weight 4 | } from '../functions' 5 | 6 | export default function motionBlur () { 7 | return convolution(weight([ 8 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 9 | 0, 1, 0, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 11 | 0, 0, 0, 1, 0, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 1, 0, 0, 0, 0, 13 | 0, 0, 0, 0, 0, 1, 0, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 15 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 16 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 17 | ], 1 / 9)); 18 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/negative.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function negative (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | -1, 0, 0, 0, 0, 11 | 0, -1, 0, 0, 0, 12 | 0, 0, -1, 0, 0, 13 | 0, 0, 0, 1, 0, 14 | 1, 1, 1, 1, 1 15 | ], amount / 100)); 16 | } 17 | -------------------------------------------------------------------------------- /src/util/filter/matrix/normal.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../functions' 4 | 5 | export default function identity () { 6 | return convolution([ 7 | 0, 0, 0, 8 | 0, 1, 0, 9 | 0, 0, 0 10 | ]); 11 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/sepia2.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function sepia2 (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | 0.393, 0.349, 0.272, 0, 0, 11 | 0.769, 0.686, 0.534, 0, 0, 12 | 0.189, 0.168, 0.131, 0, 0, 13 | 0, 0, 0, 0, 0, 14 | 0, 0, 0, 0, 0 15 | ], amount / 100)); 16 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/sharpen.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function sharpen (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | 0, -1, 0, 11 | -1, 5, -1, 12 | 0, -1, 0 13 | ], amount / 100)); 14 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/sobel-horizontal.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../functions' 4 | 5 | export default function sobelHorizontal () { 6 | return convolution([ 7 | -1, -2, -1, 8 | 0, 0, 0, 9 | 1, 2, 1 10 | ]); 11 | } 12 | -------------------------------------------------------------------------------- /src/util/filter/matrix/sobel-vertical.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../functions' 4 | 5 | export default function sobelVertical () { 6 | return convolution([ 7 | -1, 0, 1, 8 | -2, 0, 2, 9 | -1, 0, 1 10 | ]); 11 | } 12 | -------------------------------------------------------------------------------- /src/util/filter/matrix/stack-blur.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber 3 | } from '../functions' 4 | 5 | import StackBlur from '../StackBlur' 6 | 7 | export default function (radius = 10, hasAlphaChannel = true) { 8 | radius = parseParamNumber(radius) 9 | 10 | return function (bitmap, done, opt = {}) { 11 | let newBitmap = StackBlur(bitmap, radius, hasAlphaChannel ) 12 | 13 | done(newBitmap); 14 | } 15 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/transparency.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function transparency (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | 1, 0, 0, 0, 0, 11 | 0, 1, 0, 0, 0, 12 | 0, 0, 1, 0, 0, 13 | 0, 0, 0, 0.3, 0, 14 | 0, 0, 0, 0, 1, 15 | ], amount / 100)); 16 | } -------------------------------------------------------------------------------- /src/util/filter/matrix/unsharp-masking.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../functions' 6 | 7 | export default function unsharpMasking (amount = 256) { 8 | amount = parseParamNumber(amount) 9 | return convolution(weight([ 10 | 1, 4, 6, 4, 1, 11 | 4, 16, 24, 16, 4, 12 | 6, 24, -476, 24, 6, 13 | 4, 16, 24, 16, 4, 14 | 1, 4, 6, 4, 1 15 | ], -1 / amount)); 16 | } -------------------------------------------------------------------------------- /src/util/filter/multi/index.js: -------------------------------------------------------------------------------- 1 | import kirsch from './kirsch' 2 | import sobel from './sobel' 3 | import vintage from './vintage' 4 | 5 | export default { 6 | kirsch, 7 | sobel, 8 | vintage 9 | } -------------------------------------------------------------------------------- /src/util/filter/multi/kirsch.js: -------------------------------------------------------------------------------- 1 | import { 2 | filter 3 | } from '../functions' 4 | 5 | export default function kirsch () { 6 | return filter('kirsch-horizontal kirsch-vertical'); 7 | } -------------------------------------------------------------------------------- /src/util/filter/multi/sobel.js: -------------------------------------------------------------------------------- 1 | import { 2 | filter 3 | } from '../functions' 4 | 5 | export default function sobel () { 6 | return filter('sobel-horizontal sobel-vertical'); 7 | } -------------------------------------------------------------------------------- /src/util/filter/multi/vintage.js: -------------------------------------------------------------------------------- 1 | import { 2 | filter 3 | } from '../functions' 4 | 5 | export default function vintage () { 6 | return filter(`brightness(15) saturation(-20) gamma(1.8)`) 7 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/bitonal.js: -------------------------------------------------------------------------------- 1 | import Color from '../../Color' 2 | import { pixel } from '../functions' 3 | 4 | 5 | export default function bitonal(darkColor, lightColor, threshold = 100) { 6 | let $darkColor = Color.parse(darkColor); 7 | let $lightColor = Color.parse(lightColor); 8 | let $threshold = threshold 9 | 10 | return pixel(` 11 | const thresholdColor = ( $r + $g + $b ) <= $threshold ? $darkColor : $lightColor 12 | 13 | $r = thresholdColor.r 14 | $g = thresholdColor.g 15 | $b = thresholdColor.b 16 | `, { 17 | $threshold 18 | }, { 19 | $darkColor, 20 | $lightColor 21 | }) 22 | } 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/util/filter/pixel/brightness.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel, 4 | colorMatrix 5 | } from '../functions' 6 | 7 | /* 8 | * @param {Number} amount -100..100 , value < 0 is darken, value > 0 is brighten 9 | */ 10 | export default function brightness (amount = 1) { 11 | amount = parseParamNumber(amount) 12 | const $C = Math.floor(255 * (amount / 100)); 13 | 14 | return pixel(` 15 | $r += $C 16 | $g += $C 17 | $b += $C 18 | `,{ $C }) 19 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/brownie.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function brownie () { 7 | 8 | const $matrix = [ 9 | 0.5997023498159715,0.34553243048391263,-0.2708298674538042,0, 10 | -0.037703249837783157,0.8609577587992641,0.15059552388459913,0, 11 | 0.24113635128153335,-0.07441037908422492,0.44972182064877153,0, 12 | 0,0,0,1 13 | ] 14 | 15 | return pixel(` 16 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 17 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 18 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 19 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 20 | `, { 21 | $matrix 22 | }) 23 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/clip.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | /** 7 | * 8 | * @param {Number} amount from 0 to 100 9 | */ 10 | export default function clip (amount = 0) { 11 | amount = parseParamNumber(amount) 12 | const $C = Math.abs(amount) * 2.55 13 | 14 | return pixel(` 15 | 16 | $r = ($r > 255 - $C) ? 255 : 0 17 | $g = ($g > 255 - $C) ? 255 : 0 18 | $b = ($b > 255 - $C) ? 255 : 0 19 | 20 | `, { $C }) 21 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/contrast.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | /** 6 | * 7 | * @param {*} amount min = -128, max = 128 8 | */ 9 | export default function contrast(amount = 0) { 10 | amount = parseParamNumber(amount) 11 | const $C = Math.max((128 + amount) / 128, 0); 12 | 13 | return pixel(` 14 | $r *= $C 15 | $g *= $C 16 | $b *= $C 17 | `, { $C }) 18 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/gamma.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function gamma (amount = 1) { 7 | const $C = parseParamNumber(amount) 8 | return pixel(` 9 | $r = Math.pow($r / 255, $C) * 255 10 | $g = Math.pow($g / 255, $C) * 255 11 | $b = Math.pow($b / 255, $C) * 255 12 | `, { $C }) 13 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/gradient.js: -------------------------------------------------------------------------------- 1 | import Color from '../../Color' 2 | import { 3 | // clamp, 4 | pixel 5 | } from '../functions' 6 | /** 7 | * F.gradient('red', 'blue', 'yellow', 'white', 10) 8 | * F.gradient('red, blue, yellow, white, 10') 9 | */ 10 | export default function gradient () { 11 | // 전체 매개변수 기준으로 파싱 12 | // 색이 아닌 것 기준으로 scale 변수로 인식 13 | 14 | let params = [...arguments]; 15 | 16 | if (params.length === 1 && typeof params[0] === 'string') { 17 | params = Color.convertMatchesArray(params[0]) 18 | } 19 | 20 | params = params.map(arg => { 21 | const res = Color.matches(arg) 22 | 23 | if (!res.length) { 24 | return { type: 'scale', value : arg } 25 | } 26 | 27 | return { type: 'param', value : arg } 28 | }) 29 | 30 | let $scale = params.filter(it => { return it.type == 'scale' })[0] 31 | $scale = $scale ? +$scale.value : 256 32 | 33 | params = params.filter(it => { return it.type == 'param' }).map( it => { 34 | return it.value 35 | }).join(',') 36 | 37 | let $colors = Color.gradient(params, $scale).map(c => { 38 | const { r, g, b, a } = Color.parse(c) 39 | return {r, g, b, a} 40 | }) 41 | 42 | return pixel(` 43 | const colorIndex = clamp(Math.ceil($r * 0.2126 + $g * 0.7152 + $b * 0.0722)) 44 | const newColorIndex = clamp(Math.floor(colorIndex * ($scale / 256))) 45 | const color = $colors[newColorIndex] 46 | 47 | $r = color.r 48 | $g = color.g 49 | $b = color.b 50 | $a = clamp(Math.floor(color.a * 256)) 51 | `, { }, { $colors, $scale }) 52 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/grayscale.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function grayscale (amount) { 7 | amount = parseParamNumber(amount) 8 | let C = amount / 100; 9 | 10 | if (C > 1) C = 1; 11 | 12 | const $matrix = [ 13 | (0.2126 + 0.7874 * (1 - C)), (0.7152 - 0.7152 * (1 - C)), (0.0722 - 0.0722 * (1 - C)), 0, 14 | (0.2126 - 0.2126 * (1 - C)), (0.7152 + 0.2848 * (1 - C)), (0.0722 - 0.0722 * (1 - C)), 0, 15 | (0.2126 - 0.2126 * (1 - C)), (0.7152 - 0.7152 * (1 - C)), (0.0722 + 0.9278 * (1 - C)), 0, 16 | 0, 0, 0, 1 17 | ] 18 | 19 | return pixel(/*javascript*/` 20 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 21 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 22 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 23 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 24 | `, { 25 | $matrix 26 | }); 27 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/hue.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | /* 7 | * @param {Number} amount 0..360 8 | */ 9 | export default function hue (amount = 360) { 10 | const $C = parseParamNumber(amount) 11 | return pixel(` 12 | var hsv = Color.RGBtoHSV($r, $g, $b); 13 | 14 | // 0 ~ 360 15 | var h = hsv.h; 16 | h += Math.abs($C) 17 | h = h % 360 18 | hsv.h = h 19 | 20 | var rgb = Color.HSVtoRGB(hsv); 21 | 22 | $r = rgb.r 23 | $g = rgb.g 24 | $b = rgb.b 25 | `, { 26 | $C 27 | }) 28 | } 29 | -------------------------------------------------------------------------------- /src/util/filter/pixel/index.js: -------------------------------------------------------------------------------- 1 | 2 | import bitonal from './bitonal' 3 | import brightness from './brightness' 4 | import brownie from './brownie' 5 | import clip from './clip' 6 | import contrast from './contrast' 7 | import gamma from './gamma' 8 | import gradient from './gradient' 9 | import grayscale from './grayscale' 10 | import hue from './hue' 11 | import invert from './invert' 12 | import kodachrome from './kodachrome' 13 | import matrix from './matrix' 14 | import noise from './noise' 15 | import opacity from './opacity' 16 | import polaroid from './polaroid' 17 | import saturation from './saturation' 18 | import sepia from './sepia' 19 | import shade from './shade' 20 | import shift from './shift' 21 | import solarize from './solarize' 22 | import technicolor from './technicolor' 23 | import threshold from './threshold' 24 | import thresholdColor from './threshold-color' 25 | import tint from './tint' 26 | 27 | export default { 28 | bitonal, 29 | brightness, 30 | brownie, 31 | clip, 32 | contrast, 33 | gamma, 34 | gradient, 35 | grayscale, 36 | hue, 37 | invert, 38 | kodachrome, 39 | matrix, 40 | noise, 41 | opacity, 42 | polaroid, 43 | saturation, 44 | sepia, 45 | shade, 46 | shift, 47 | solarize, 48 | technicolor, 49 | threshold, 50 | 'threshold-color': thresholdColor, 51 | tint 52 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/invert.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | export default function invert (amount = 100) { 6 | amount = parseParamNumber(amount) 7 | const $C = amount / 100; 8 | 9 | return pixel(` 10 | $r = (255 - $r) * $C 11 | $g = (255 - $g) * $C 12 | $b = (255 - $b) * $C 13 | `, { 14 | $C 15 | }) 16 | } 17 | -------------------------------------------------------------------------------- /src/util/filter/pixel/kodachrome.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function kodachrome () { 7 | 8 | const $matrix = [ 9 | 1.1285582396593525,-0.3967382283601348,-0.03992559172921793,0, 10 | -0.16404339962244616,1.0835251566291304,-0.05498805115633132,0, 11 | -0.16786010706155763,-0.5603416277695248,1.6014850761964943,0, 12 | 0,0,0,1 13 | ] 14 | 15 | return pixel(` 16 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 17 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 18 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 19 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 20 | `, { 21 | $matrix 22 | }) 23 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/matrix.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function matrix ( 7 | $a = 0, $b = 0, $c = 0, $d = 0, 8 | $e = 0, $f = 0, $g = 0, $h = 0, 9 | $i = 0, $j = 0, $k = 0, $l = 0, 10 | $m = 0, $n = 0, $o = 0, $p = 0 11 | ) { 12 | 13 | const $matrix = [ 14 | $a, $b, $c, $d, 15 | $e, $f, $g, $h, 16 | $i, $j, $k, $l, 17 | $m, $n, $o, $p 18 | ] 19 | 20 | return pixel(` 21 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 22 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 23 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 24 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 25 | `, { 26 | $matrix 27 | }) 28 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/noise.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | /** 7 | * 8 | * @param {Number} amount 1..100 9 | */ 10 | export default function noise (amount = 1) { 11 | const $C = parseParamNumber(amount) 12 | return pixel(` 13 | const C = Math.abs($C) * 5 14 | const min = -C 15 | const max = C 16 | const noiseValue = Math.round(min + (Math.random() * (max - min))) 17 | 18 | $r += noiseValue 19 | $g += noiseValue 20 | $b += noiseValue 21 | `, { 22 | $C 23 | }) 24 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/opacity.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | 7 | export default function opacity (amount = 100) { 8 | amount = parseParamNumber(amount) 9 | const $C = amount / 100; 10 | 11 | return pixel(` 12 | $a *= $C 13 | `, { $C }) 14 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/polaroid.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function polaroid () { 7 | 8 | const $matrix = [ 9 | 1.438,-0.062,-0.062,0, 10 | -0.122,1.378,-0.122,0, 11 | -0.016,-0.016,1.483,0, 12 | 0,0,0,1 13 | ] 14 | 15 | return pixel(` 16 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 17 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 18 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 19 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 20 | `, { 21 | $matrix 22 | }) 23 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/saturation.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | /* 7 | * @param {Number} amount -100..100 8 | */ 9 | export default function saturation (amount = 100) { 10 | amount = parseParamNumber(amount) 11 | const C = amount / 100 12 | const L = 1 - Math.abs(C); 13 | 14 | const $matrix = [ 15 | L, 0, 0, 0, 16 | 0, L, 0, 0, 17 | 0, 0, L, 0, 18 | 0, 0, 0, L 19 | ] 20 | 21 | return pixel(` 22 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 23 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 24 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 25 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 26 | `, { 27 | $matrix 28 | }) 29 | 30 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/sepia.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | /* 7 | * @param {Number} amount 0..1 8 | */ 9 | export default function sepia (amount = 1) { 10 | let C = parseParamNumber(amount); 11 | if (C > 1) C = 1; 12 | 13 | const $matrix = [ 14 | (0.393 + 0.607 * (1 - C)), (0.769 - 0.769 * (1 - C)), (0.189 - 0.189 * (1 - C)), 0, 15 | (0.349 - 0.349 * (1 - C)), (0.686 + 0.314 * (1 - C)), (0.168 - 0.168 * (1 - C)), 0, 16 | (0.272 - 0.272 * (1 - C)), (0.534 - 0.534 * (1 - C)), (0.131 + 0.869 * (1 - C)), 0, 17 | 0, 0, 0, 1 18 | ] 19 | 20 | return pixel(` 21 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 22 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 23 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 24 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 25 | `, { 26 | $matrix 27 | }) 28 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/shade.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function shade(redValue = 1, greenValue = 1, blueValue = 1) { 7 | const $redValue = parseParamNumber(redValue) 8 | const $greenValue = parseParamNumber(greenValue) 9 | const $blueValue = parseParamNumber(blueValue) 10 | 11 | return pixel(` 12 | $r *= $redValue 13 | $g *= $greenValue 14 | $b *= $blueValue 15 | `, { 16 | $redValue, 17 | $greenValue, 18 | $blueValue 19 | }) 20 | 21 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/shift.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function shift () { 7 | 8 | const $matrix = [ 9 | 1.438,-0.062,-0.062,0, 10 | -0.122,1.378,-0.122,0, 11 | -0.016,-0.016,1.483,0, 12 | 0,0,0,1 13 | ] 14 | 15 | return pixel(` 16 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 17 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 18 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 19 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 20 | `, { 21 | $matrix 22 | }) 23 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/solarize.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | /** 6 | * change the relative darkness of (a part of an image) by overexposure to light. 7 | * @param {*} r 8 | * @param {*} g 9 | * @param {*} b 10 | */ 11 | export default function solarize (redValue, greenValue, blueValue) { 12 | const $redValue = parseParamNumber(redValue) 13 | const $greenValue = parseParamNumber(greenValue) 14 | const $blueValue = parseParamNumber(blueValue) 15 | return pixel(` 16 | $r = ($r < $redValue) ? 255 - $r: $r 17 | $g = ($g < $greenValue) ? 255 - $g: $g 18 | $b = ($b < $blueValue) ? 255 - $b: $b 19 | `, { 20 | $redValue, $greenValue, $blueValue 21 | }) 22 | 23 | } 24 | -------------------------------------------------------------------------------- /src/util/filter/pixel/technicolor.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | export default function technicolor () { 7 | 8 | const $matrix = [ 9 | 1.9125277891456083,-0.8545344976951645,-0.09155508482755585,0, 10 | -0.3087833385928097,1.7658908555458428,-0.10601743074722245,0, 11 | -0.231103377548616,-0.7501899197440212,1.847597816108189,0, 12 | 0,0,0,1 13 | ] 14 | 15 | return pixel(` 16 | $r = $matrix[0] * $r + $matrix[1] * $g + $matrix[2] * $b + $matrix[3] * $a 17 | $g = $matrix[4] * $r + $matrix[5] * $g + $matrix[6] * $b + $matrix[7] * $a 18 | $b = $matrix[8] * $r + $matrix[9] * $g + $matrix[10] * $b + $matrix[11] * $a 19 | $a = $matrix[12] * $r + $matrix[13] * $g + $matrix[14] * $b + $matrix[15] * $a 20 | `, { 21 | $matrix 22 | }) 23 | } -------------------------------------------------------------------------------- /src/util/filter/pixel/threshold-color.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | pixel 4 | } from '../functions' 5 | 6 | 7 | export default function thresholdColor (scale = 200, amount = 100, hasColor = true) { 8 | const $scale = parseParamNumber(scale) 9 | amount = parseParamNumber(amount) 10 | const $C = amount / 100; 11 | const $hasColor = hasColor 12 | 13 | return pixel(` 14 | // refer to Color.brightness 15 | const v = ($C * Math.ceil($r * 0.2126 + $g * 0.7152 + $b * 0.0722) ) >= $scale ? 255 : 0; 16 | 17 | if ($hasColor) { 18 | 19 | if (v == 0) { 20 | $r = 0 21 | $g = 0 22 | $b = 0 23 | } 24 | 25 | } else { 26 | const value = Math.round(v) 27 | $r = value 28 | $g = value 29 | $b = value 30 | } 31 | 32 | `, { 33 | $C, $scale, $hasColor 34 | }) 35 | } 36 | -------------------------------------------------------------------------------- /src/util/filter/pixel/threshold.js: -------------------------------------------------------------------------------- 1 | import thresholdColor from './threshold-color' 2 | /* 3 | * @param {Number} amount 0..100 4 | */ 5 | export default function threshold (scale = 200, amount = 100) { 6 | return thresholdColor(scale, amount, false) 7 | } 8 | -------------------------------------------------------------------------------- /src/util/filter/pixel/tint.js: -------------------------------------------------------------------------------- 1 | import { pixel, parseParamNumber } from "../functions"; 2 | 3 | 4 | export default function (redTint = 1, greenTint = 1, blueTint = 1) { 5 | const $redTint = parseParamNumber(redTint) 6 | const $greenTint = parseParamNumber(greenTint) 7 | const $blueTint = parseParamNumber(blueTint) 8 | return pixel(` 9 | 10 | $r += (255 - $r) * $redTint 11 | $g += (255 - $g) * $greenTint 12 | $b += (255 - $b) * $blueTint 13 | 14 | `, { 15 | $redTint, 16 | $greenTint, 17 | $blueTint 18 | }) 19 | 20 | } -------------------------------------------------------------------------------- /src/util/functions/formatter.js: -------------------------------------------------------------------------------- 1 | 2 | /** 3 | * @method format 4 | * 5 | * convert color to format string 6 | * 7 | * // hex 8 | * color.format({ r : 255, g : 255, b : 255, a: 1 }, 'hex') // #FFFFFFFF 9 | * 10 | * // rgb 11 | * color.format({ r : 255, g : 255, b : 255 }, 'rgb') // rgba(255, 255, 255, 0.5); 12 | * 13 | * // rgba 14 | * color.format({ r : 255, g : 255, b : 255, a : 0.5 }, 'rgb') // rgba(255, 255, 255, 0.5); 15 | * 16 | * @param {Object} obj obj has r, g, b and a attributes 17 | * @param {"hex"/"rgb"} type format string type 18 | * @returns {*} 19 | */ 20 | export function format(obj, type, defaultColor = 'rgba(0, 0, 0, 0)') { 21 | 22 | if (Array.isArray(obj)) { 23 | obj = { r: obj[0], g: obj[1], b: obj[2], a: obj[3] } 24 | } 25 | 26 | if (type == 'hex') { 27 | return hex(obj); 28 | } else if (type == 'rgb') { 29 | return rgb(obj, defaultColor); 30 | } else if (type == 'hsl') { 31 | return hsl(obj); 32 | } 33 | 34 | return obj; 35 | } 36 | 37 | export function hex(obj) { 38 | if (Array.isArray(obj)) { 39 | obj = { r: obj[0], g: obj[1], b: obj[2], a: obj[3] } 40 | } 41 | 42 | var r = obj.r.toString(16); 43 | if (obj.r < 16) r = "0" + r; 44 | 45 | var g = obj.g.toString(16); 46 | if (obj.g < 16) g = "0" + g; 47 | 48 | var b = obj.b.toString(16); 49 | if (obj.b < 16) b = "0" + b; 50 | 51 | 52 | var alphaValue = '' 53 | if (obj.a < 1) { 54 | var alpha = Math.floor(obj.a * 255) 55 | var alphaValue = alpha.toString(16); 56 | if (alpha < 16) alphaValue = "0" + alphaValue; 57 | } 58 | 59 | return `#${r}${g}${b}${alphaValue}`; 60 | } 61 | 62 | export function rgb (obj, defaultColor = 'rgba(0, 0, 0, 0)') { 63 | if (Array.isArray(obj)) { 64 | obj = { r: obj[0], g: obj[1], b: obj[2], a: obj[3] } 65 | } 66 | 67 | if (typeof obj == 'undefined') { 68 | return undefined; 69 | } 70 | 71 | if (obj.a == 1 || typeof obj.a == 'undefined') { 72 | if (isNaN(obj.r)) { 73 | return defaultColor; 74 | } 75 | return `rgb(${obj.r},${obj.g},${obj.b})`; 76 | } else { 77 | return `rgba(${obj.r},${obj.g},${obj.b},${obj.a})`; 78 | } 79 | } 80 | 81 | export function hsl (obj) { 82 | if (Array.isArray(obj)) { 83 | obj = { r: obj[0], g: obj[1], b: obj[2], a: obj[3] } 84 | } 85 | 86 | if (obj.a == 1 || typeof obj.a == 'undefined') { 87 | return `hsl(${obj.h},${obj.s}%,${obj.l}%)`; 88 | } else { 89 | return `hsla(${obj.h},${obj.s}%,${obj.l}%,${obj.a})`; 90 | } 91 | 92 | } 93 | 94 | export default { 95 | format, 96 | rgb, 97 | hsl, 98 | hex 99 | }; -------------------------------------------------------------------------------- /src/util/functions/fromCMYK.js: -------------------------------------------------------------------------------- 1 | 2 | export function CMYKtoRGB(c, m, y, k) { 3 | 4 | if (arguments.length == 1) { 5 | var { c, m, y, k } = arguments[0]; 6 | } 7 | 8 | const R = 255 * (1 - c) * (1 - k); 9 | const G = 255 * (1 - m) * (1 - k); 10 | const B = 255 * (1 - y) * (1 - k); 11 | 12 | return { r: R, g: G, b: B } 13 | } 14 | 15 | export default { 16 | CMYKtoRGB 17 | } -------------------------------------------------------------------------------- /src/util/functions/fromHSL.js: -------------------------------------------------------------------------------- 1 | import { RGBtoHSV } from './fromRGB' 2 | import { round } from './math' 3 | 4 | export function HUEtoRGB(p, q, t) { 5 | if (t < 0) t += 1; 6 | if (t > 1) t -= 1; 7 | if (t < 1 / 6) return p + (q - p) * 6 * t; 8 | if (t < 1 / 2) return q; 9 | if (t < 2 / 3) return p + (q - p) * (2 / 3 - t) * 6; 10 | return p; 11 | } 12 | 13 | export function HSLtoHSV(h, s, l) { 14 | 15 | if (arguments.length == 1) { 16 | var { h, s, l } = arguments[0]; 17 | } 18 | const rgb = HSLtoRGB(h, s, l); 19 | 20 | return RGBtoHSV(rgb.r, rgb.g, rgb.b); 21 | } 22 | 23 | export function HSLtoRGB(h, s, l) { 24 | 25 | if (arguments.length == 1) { 26 | var { h, s, l } = arguments[0]; 27 | } 28 | 29 | var r, g, b; 30 | 31 | h /= 360; 32 | s /= 100; 33 | l /= 100; 34 | 35 | if (s == 0) { 36 | r = g = b = l; // achromatic 37 | } else { 38 | var q = l < 0.5 ? l * (1 + s) : l + s - l * s; 39 | var p = 2 * l - q; 40 | r = HUEtoRGB(p, q, h + 1 / 3); 41 | g = HUEtoRGB(p, q, h); 42 | b = HUEtoRGB(p, q, h - 1 / 3); 43 | } 44 | 45 | return { r: round(r * 255), g: round(g * 255), b: round(b * 255) }; 46 | } 47 | 48 | export default { 49 | HUEtoRGB, 50 | HSLtoHSV, 51 | HSLtoRGB 52 | } -------------------------------------------------------------------------------- /src/util/functions/fromHSV.js: -------------------------------------------------------------------------------- 1 | import { round } from './math' 2 | import { RGBtoHSL } from './fromRGB' 3 | 4 | /** 5 | * @method HSVtoRGB 6 | * 7 | * convert hsv to rgb 8 | * 9 | * color.HSVtoRGB(0,0,1) === #FFFFF === { r : 255, g : 0, b : 0 } 10 | * 11 | * @param {Number} H hue color number (min : 0, max : 360) 12 | * @param {Number} S Saturation number (min : 0, max : 1) 13 | * @param {Number} V Value number (min : 0, max : 1 ) 14 | * @returns {Object} 15 | */ 16 | export function HSVtoRGB(h, s, v) { 17 | 18 | if (arguments.length == 1) { 19 | var { h, s, v } = arguments[0]; 20 | } 21 | 22 | var H = h; 23 | var S = s; 24 | var V = v; 25 | 26 | if (H >= 360) { 27 | H = 0; 28 | } 29 | 30 | const C = S * V; 31 | const X = C * (1 - Math.abs((H / 60) % 2 - 1)); 32 | const m = V - C; 33 | 34 | let temp = []; 35 | 36 | if (0 <= H && H < 60) { temp = [C, X, 0]; } 37 | else if (60 <= H && H < 120) { temp = [X, C, 0]; } 38 | else if (120 <= H && H < 180) { temp = [0, C, X]; } 39 | else if (180 <= H && H < 240) { temp = [0, X, C]; } 40 | else if (240 <= H && H < 300) { temp = [X, 0, C]; } 41 | else if (300 <= H && H < 360) { temp = [C, 0, X]; } 42 | 43 | return { 44 | r: round((temp[0] + m) * 255), 45 | g: round((temp[1] + m) * 255), 46 | b: round((temp[2] + m) * 255) 47 | }; 48 | } 49 | 50 | export function HSVtoHSL(h, s, v) { 51 | 52 | if (arguments.length == 1) { 53 | var { h, s, v } = arguments[0]; 54 | } 55 | 56 | const rgb = HSVtoRGB(h, s, v); 57 | 58 | return RGBtoHSL(rgb.r, rgb.g, rgb.b); 59 | } 60 | 61 | export default { 62 | HSVtoHSL, 63 | HSVtoRGB 64 | } -------------------------------------------------------------------------------- /src/util/functions/fromLAB.js: -------------------------------------------------------------------------------- 1 | import { round } from './math' 2 | 3 | export function ReverseXyz(n) { 4 | return (Math.pow(n, 3) > 0.008856) ? Math.pow(n, 3) : (n - 16 / 116) / 7.787; 5 | } 6 | 7 | export function ReverseRGB(n) { 8 | return (n > 0.0031308) ? 1.055 * (Math.pow(n, (1 / 2.4))) - 0.055 : 12.92 * n; 9 | } 10 | 11 | export function XYZtoRGB(x, y, z) { 12 | if (arguments.length == 1) { 13 | var { x, y, z } = arguments[0]; 14 | } 15 | //X, Y and Z input refer to a D65/2° standard illuminant. 16 | //sR, sG and sB (standard RGB) output range = 0 ÷ 255 17 | 18 | let X = x / 100.0 19 | let Y = y / 100.0 20 | let Z = z / 100.0 21 | 22 | let R = X * 3.2406 + Y * -1.5372 + Z * -0.4986; 23 | let G = X * -0.9689 + Y * 1.8758 + Z * 0.0415; 24 | let B = X * 0.0557 + Y * -0.2040 + Z * 1.0570; 25 | 26 | R = ReverseRGB(R); 27 | G = ReverseRGB(G); 28 | B = ReverseRGB(B); 29 | 30 | const r = round(R * 255); 31 | const g = round(G * 255); 32 | const b = round(B * 255); 33 | 34 | return { r, g, b }; 35 | } 36 | 37 | export function LABtoXYZ(l, a, b) { 38 | if (arguments.length == 1) { 39 | var { l, a, b } = arguments[0]; 40 | } 41 | //Reference-X, Y and Z refer to specific illuminants and observers. 42 | //Common reference values are available below in this same page. 43 | 44 | let Y = (l + 16) / 116 45 | let X = a / 500 + Y 46 | let Z = Y - b / 200 47 | 48 | Y = ReverseXyz(Y); 49 | X = ReverseXyz(X); 50 | Z = ReverseXyz(Z); 51 | 52 | const x = X * 95.047 53 | const y = Y * 100.000 54 | const z = Z * 108.883 55 | 56 | return { x, y, z }; 57 | } 58 | 59 | export function PivotXyz(n) { 60 | return (n > 0.008856) ? Math.pow(n, (1 / 3)) : (7.787 * n + 16) / 116; 61 | } 62 | 63 | 64 | export function XYZtoLAB(x, y, z) { 65 | if (arguments.length == 1) { 66 | var { x, y, z } = arguments[0]; 67 | } 68 | 69 | //Reference-X, Y and Z refer to specific illuminants and observers. 70 | //Common reference values are available below in this same page. 71 | // Observer= 2°, Illuminant= D65 72 | 73 | let X = x / 95.047; 74 | let Y = y / 100.00; 75 | let Z = z / 108.883; 76 | 77 | X = PivotXyz(X); 78 | Y = PivotXyz(Y); 79 | Z = PivotXyz(Z); 80 | 81 | const l = (116 * Y) - 16; 82 | const a = 500 * (X - Y); 83 | const b = 200 * (Y - Z); 84 | 85 | return { l, a, b }; 86 | } 87 | 88 | export function LABtoRGB(l, a, b) { 89 | if (arguments.length == 1) { 90 | var { l, a, b } = arguments[0]; 91 | } 92 | return XYZtoRGB(LABtoXYZ(l, a, b)); 93 | } 94 | 95 | export default { 96 | XYZtoRGB, 97 | LABtoRGB, 98 | LABtoXYZ 99 | } -------------------------------------------------------------------------------- /src/util/functions/fromYCrCb.js: -------------------------------------------------------------------------------- 1 | export function YCrCbtoRGB(y, cr, cb, bit) { 2 | 3 | if (arguments.length == 1) { 4 | var { y, cr, cb, bit } = arguments[0]; 5 | bit = bit || 0; 6 | } 7 | const R = y + 1.402 * (cr - bit); 8 | const G = y - 0.344 * (cb - bit) - 0.714 * (cr - bit); 9 | const B = y + 1.772 * (cb - bit); 10 | 11 | return { r: Math.ceil(R), g: Math.ceil(G), b: Math.ceil(B) } 12 | } 13 | 14 | export default { 15 | YCrCbtoRGB 16 | } -------------------------------------------------------------------------------- /src/util/functions/math.js: -------------------------------------------------------------------------------- 1 | export function round (n, k) { 2 | k = typeof k == 'undefined' ? 1 : k; 3 | return Math.round(n * k) / k; 4 | } 5 | 6 | 7 | export function degreeToRadian (angle) { 8 | return angle * Math.PI / 180; 9 | } 10 | 11 | /** 12 | * 13 | * convert radian to degree 14 | * 15 | * @param {*} radian 16 | * @returns {Number} 0..360 17 | */ 18 | export function radianToDegree(radian) { 19 | var angle = radian * 180 / Math.PI; 20 | 21 | 22 | if (angle < 0) { // 각도가 0보다 작으면 360 에서 반전시킨다. 23 | angle = 360 + angle 24 | } 25 | 26 | return angle; 27 | } 28 | 29 | 30 | export function getXInCircle (angle, radius, centerX = 0) { 31 | return centerX + radius * Math.cos(degreeToRadian (angle)) 32 | } 33 | 34 | export function getYInCircle (angle, radius, centerY = 0) { 35 | return centerY + radius * Math.sin(degreeToRadian(angle)) 36 | } 37 | 38 | export function getXYInCircle (angle, radius, centerX = 0, centerY = 0) { 39 | return { 40 | x : getXInCircle(angle, radius, centerX), 41 | y : getYInCircle(angle, radius, centerY) 42 | } 43 | } 44 | 45 | export function caculateAngle (rx, ry) { 46 | return radianToDegree(Math.atan2(ry, rx)) 47 | } 48 | 49 | export default { 50 | round, 51 | radianToDegree, 52 | degreeToRadian, 53 | getXInCircle, 54 | getYInCircle, 55 | caculateAngle 56 | } -------------------------------------------------------------------------------- /src/util/functions/support.js: -------------------------------------------------------------------------------- 1 | function isSupported(api, apiParent) { 2 | return (api in apiParent); 3 | } 4 | 5 | export const enableEyeDropper = isSupported('EyeDropper', window); -------------------------------------------------------------------------------- /src/util/gl/filter/index.js: -------------------------------------------------------------------------------- 1 | import matrix from './matrix/index' 2 | import pixel from './pixel/index' 3 | import multi from './multi/index' 4 | 5 | export default { 6 | ...matrix, 7 | ...pixel, 8 | ...multi 9 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/blur.js: -------------------------------------------------------------------------------- 1 | import { convolution } from '../util' 2 | 3 | export default function () { 4 | return convolution([ 5 | 1, 1, 1, 6 | 1, 1, 1, 7 | 1, 1, 1 8 | ]) 9 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/emboss.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution 4 | } from '../util' 5 | /* 6 | * carve, mold, or stamp a design on (a surface) so that it stands out in relief. 7 | * 8 | * @param {Number} amount 0.0 .. 4.0 9 | */ 10 | export default function emboss (amount = 4) { 11 | amount = parseParamNumber(amount) 12 | return convolution([ 13 | amount * (-2.0), -amount, 0.0, 14 | -amount, 1.0, amount, 15 | 0.0, amount, amount * 2.0, 16 | ]); 17 | } 18 | -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/gaussian-blur-5x.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../util' 6 | 7 | export default function gaussianBlur5x () { 8 | return convolution([ 9 | 1, 4, 6, 4, 1, 10 | 4, 16, 24, 16, 4, 11 | 6, 24, 36, 24, 6, 12 | 4, 16, 24, 16, 4, 13 | 1, 4, 6, 4, 1 14 | ]); 15 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/gaussian-blur.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | convolution, 4 | weight 5 | } from '../util' 6 | 7 | /** 8 | * 9 | * @param {Number} amount 0..1 10 | */ 11 | export default function gaussianBlur (amount = 1) { 12 | const C = parseParamNumber(amount) * (1/16) 13 | 14 | return convolution(weight([ 15 | 1, 2, 1, 16 | 2, 4, 2, 17 | 1, 2, 1 18 | ], C )); 19 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/grayscale2.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function grayscale2 () { 6 | return convolution([ 7 | 0.3, 0.3, 0.3, 0, 0, 8 | 0.59, 0.59, 0.59, 0, 0, 9 | 0.11, 0.11, 0.11, 0, 0, 10 | 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0 12 | ]); 13 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/index.js: -------------------------------------------------------------------------------- 1 | import blur from './blur' 2 | import normal from './normal' 3 | import emboss from './emboss' 4 | import gaussianBlur from './gaussian-blur' 5 | import gaussianBlur5x from './gaussian-blur-5x' 6 | import grayscale2 from './grayscale2' 7 | import kirschHorizontal from './kirsch-horizontal' 8 | import kirschVertical from './kirsch-vertical' 9 | import laplacian from './laplacian' 10 | import laplacian5x from './laplacian-5x' 11 | import motionBlur from './motion-blur' 12 | import motionBlur2 from './motion-blur-2' 13 | import motionBlur3 from './motion-blur-3' 14 | import negative from './negative' 15 | import sepia2 from './sepia2' 16 | import sharpen from './sharpen' 17 | import sobelHorizontal from './sobel-horizontal' 18 | import sobelVertical from './sobel-vertical' 19 | import transparency from './transparency' 20 | import unsharpMasking from './unsharp-masking' 21 | 22 | 23 | export default { 24 | blur, 25 | normal, 26 | emboss, 27 | gaussianBlur, 28 | 'gaussian-blur': gaussianBlur, 29 | gaussianBlur5x, 30 | 'gaussian-blur-5x': gaussianBlur5x, 31 | grayscale2, 32 | kirschHorizontal, 33 | 'kirsch-horizontal': kirschHorizontal, 34 | kirschVertical, 35 | 'kirsch-vertical': kirschVertical, 36 | laplacian, 37 | laplacian5x, 38 | 'laplacian-5x': laplacian5x, 39 | motionBlur, 40 | 'motion-blur': motionBlur, 41 | motionBlur2, 42 | 'motion-blur-2': motionBlur2, 43 | motionBlur3, 44 | 'motion-blur-3': motionBlur3, 45 | negative, 46 | sepia2, 47 | sharpen, 48 | sobelHorizontal, 49 | 'sobel-horizontal': sobelHorizontal, 50 | sobelVertical, 51 | 'sobel-vertical': sobelVertical, 52 | transparency, 53 | unsharpMasking, 54 | 'unsharp-masking': unsharpMasking 55 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/kirsch-horizontal.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function kirschHorizontal () { 6 | return convolution([ 7 | 5, 5, 5, 8 | -3, 0, -3, 9 | -3, -3, -3 10 | ]); 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/kirsch-vertical.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function kirschVertical () { 6 | return convolution([ 7 | 5, -3, -3, 8 | 5, 0, -3, 9 | 5, -3, -3 10 | ]); 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/laplacian-5x.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function laplacian5x () { 6 | return convolution([ 7 | -1, -1, -1, -1, -1, 8 | -1, -1, -1, -1, -1, 9 | -1, -1, 24, -1, -1, 10 | -1, -1, -1, -1, -1, 11 | -1, -1, -1, -1, -1 12 | ]); 13 | } 14 | -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/laplacian.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function laplacian () { 6 | return convolution([ 7 | -1, -1, -1, 8 | -1, 8, -1, 9 | -1, -1, -1 10 | ]); 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/motion-blur-2.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function motionBlur2 () { 6 | return convolution([ 7 | 1, 0, 0, 0, 0, 0, 0, 0, 1, 8 | 0, 1, 0, 0, 0, 0, 0, 1, 0, 9 | 0, 0, 1, 0, 0, 0, 1, 0, 0, 10 | 0, 0, 0, 1, 0, 1, 0, 0, 0, 11 | 0, 0, 0, 0, 1, 0, 0, 0, 0, 12 | 0, 0, 0, 1, 0, 1, 0, 0, 0, 13 | 0, 0, 1, 0, 0, 0, 1, 0, 0, 14 | 0, 1, 0, 0, 0, 0, 0, 1, 0, 15 | 1, 0, 0, 0, 0, 0, 0, 0, 1, 16 | ]); 17 | } 18 | -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/motion-blur-3.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function motionBlur3 () { 6 | return convolution([ 7 | 1, 0, 0, 0, 1, 0, 0, 0, 1, 8 | 0, 1, 0, 0, 1, 0, 0, 1, 0, 9 | 0, 0, 1, 0, 1, 0, 1, 0, 0, 10 | 0, 0, 0, 1, 1, 1, 0, 0, 0, 11 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 12 | 0, 0, 0, 1, 1, 1, 0, 0, 0, 13 | 0, 0, 1, 0, 1, 0, 1, 0, 0, 14 | 0, 1, 0, 0, 1, 0, 0, 1, 0, 15 | 1, 0, 0, 0, 1, 0, 0, 0, 1, 16 | ]); 17 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/motion-blur.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function motionBlur () { 6 | return convolution([ 7 | 1, 0, 0, 0, 0, 0, 0, 0, 0, 8 | 0, 1, 0, 0, 0, 0, 0, 0, 0, 9 | 0, 0, 1, 0, 0, 0, 0, 0, 0, 10 | 0, 0, 0, 1, 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 1, 0, 0, 0, 0, 12 | 0, 0, 0, 0, 0, 1, 0, 0, 0, 13 | 0, 0, 0, 0, 0, 0, 1, 0, 0, 14 | 0, 0, 0, 0, 0, 0, 0, 1, 0, 15 | 0, 0, 0, 0, 0, 0, 0, 0, 1, 16 | ]); 17 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/negative.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function negative () { 6 | return convolution([ 7 | -1, 0, 0, 0, 0, 8 | 0, -1, 0, 0, 0, 9 | 0, 0, -1, 0, 0, 10 | 0, 0, 0, 1, 0, 11 | 1, 1, 1, 1, 1 12 | ]); 13 | } 14 | -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/normal.js: -------------------------------------------------------------------------------- 1 | import { convolution } from '../util' 2 | export default function () { 3 | return convolution([ 4 | 0, 0, 0, 5 | 0, 1, 0, 6 | 0, 0, 0 7 | ]) 8 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/sepia2.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function sepia2 () { 6 | return convolution([ 7 | 0.393, 0.349, 0.272, 0, 0, 8 | 0.769, 0.686, 0.534, 0, 0, 9 | 0.189, 0.168, 0.131, 0, 0, 10 | 0, 0, 0, 0, 0, 11 | 0, 0, 0, 0, 0 12 | ]); 13 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/sharpen.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function sharpen () { 6 | return convolution([ 7 | 0, -1, 0, 8 | -1, 5, -1, 9 | 0, -1, 0 10 | ]); 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/sobel-horizontal.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function sobelHorizontal () { 6 | return convolution([ 7 | -1, -2, -1, 8 | 0, 0, 0, 9 | 1, 2, 1 10 | ]); 11 | } 12 | -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/sobel-vertical.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function sobelVertical () { 6 | return convolution([ 7 | -1, 0, 1, 8 | -2, 0, 2, 9 | -1, 0, 1 10 | ]); 11 | } 12 | -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/transparency.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution 3 | } from '../util' 4 | 5 | export default function transparency () { 6 | return convolution([ 7 | 1, 0, 0, 0, 0, 8 | 0, 1, 0, 0, 0, 9 | 0, 0, 1, 0, 0, 10 | 0, 0, 0, 0.3, 0, 11 | 0, 0, 0, 0, 1, 12 | ]); 13 | } -------------------------------------------------------------------------------- /src/util/gl/filter/matrix/unsharp-masking.js: -------------------------------------------------------------------------------- 1 | import { 2 | convolution, 3 | weight 4 | } from '../util' 5 | 6 | export default function unsharpMasking () { 7 | return convolution(weight([ 8 | 1, 4, 6, 4, 1, 9 | 4, 16, 24, 16, 4, 10 | 6, 24, -476, 24, 6, 11 | 4, 16, 24, 16, 4, 12 | 1, 4, 6, 4, 1 13 | ], -1 / 256)); 14 | } -------------------------------------------------------------------------------- /src/util/gl/filter/multi/index.js: -------------------------------------------------------------------------------- 1 | import kirsch from './kirsch' 2 | import sobel from './sobel' 3 | import vintage from './vintage' 4 | 5 | export default { 6 | kirsch, 7 | sobel, 8 | vintage 9 | } -------------------------------------------------------------------------------- /src/util/gl/filter/multi/kirsch.js: -------------------------------------------------------------------------------- 1 | import { 2 | multi 3 | } from '../util' 4 | 5 | export default function kirsch () { 6 | return multi('kirsch-horizontal kirsch-vertical'); 7 | } -------------------------------------------------------------------------------- /src/util/gl/filter/multi/sobel.js: -------------------------------------------------------------------------------- 1 | import { 2 | multi 3 | } from '../util' 4 | 5 | export default function sobel () { 6 | return multi('sobel-horizontal sobel-vertical'); 7 | } -------------------------------------------------------------------------------- /src/util/gl/filter/multi/vintage.js: -------------------------------------------------------------------------------- 1 | import { 2 | multi 3 | } from '../util' 4 | 5 | export default function vintage () { 6 | return multi(`brightness(0.15) saturation(-0.2) gamma(1.8)`) 7 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/bitonal.js: -------------------------------------------------------------------------------- 1 | import Color from '../../../Color' 2 | import { 3 | shader, 4 | colorToVec4, 5 | toFloatString 6 | } from '../util' 7 | 8 | export default function bitonal(darkColor, lightColor, threshold = 0.5) { 9 | let checkVlue = toFloatString(threshold) 10 | let darkColorString = colorToVec4(Color.parse(darkColor)) 11 | let lightColorString = colorToVec4(Color.parse(lightColor)) 12 | 13 | return shader(` 14 | if ((pixelColor.r + pixelColor.g + pixelColor.b) > ${checkVlue}) { 15 | outColor = vec4(${lightColorString}.rgb, pixelColor.a); 16 | } else { 17 | outColor = vec4(${darkColorString}.rgb, pixelColor.a); 18 | } 19 | `); 20 | } 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/brightness.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, toFloatString, parseParamNumber 3 | } from '../util' 4 | 5 | /* 6 | * @param {Number} amount -1..1 , value < 0 is darken, value > 0 is brighten 7 | */ 8 | export default function brightness (amount = 1) { 9 | const C = toFloatString( parseParamNumber(amount) ); 10 | 11 | return shader(` 12 | outColor = pixelColor + (${C}); 13 | `); 14 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/brownie.js: -------------------------------------------------------------------------------- 1 | import matrix from './matrix' 2 | 3 | export default function brownie () { 4 | 5 | return matrix( 6 | 0.5997023498159715,0.34553243048391263,-0.2708298674538042,0, 7 | -0.037703249837783157,0.8609577587992641,0.15059552388459913,0, 8 | 0.24113635128153335,-0.07441037908422492,0.44972182064877153,0, 9 | 0,0,0,1 10 | ) 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/chaos.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | export default function chaos (amount = 10) { 8 | const C = toFloatString( parseParamNumber(amount) ); 9 | 10 | return shader(` 11 | vec2 st = pixelColor.st; 12 | st *= ${C}; 13 | 14 | vec2 ipos = floor(st); // get the integer coords 15 | 16 | vec3 color = vec3(random( ipos )); 17 | 18 | outColor = vec4(color, pixelColor.a); 19 | `); 20 | } 21 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/clip.js: -------------------------------------------------------------------------------- 1 | 2 | import { 3 | shader, toFloatString, parseParamNumber 4 | } from '../util' 5 | 6 | /* 7 | * @param {Number} amount 0..1 8 | */ 9 | export default function clip (amount = 0) { 10 | const C = toFloatString(parseParamNumber(amount)) 11 | 12 | return shader(` 13 | outColor = vec4( 14 | (pixelColor.r > 1.0 - ${C}) ? 1.0 : 0.0, 15 | (pixelColor.g > 1.0 - ${C}) ? 1.0 : 0.0, 16 | (pixelColor.b > 1.0 - ${C}) ? 1.0 : 0.0, 17 | pixelColor.a 18 | ); 19 | `); 20 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/contrast.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | /* 8 | * @param {Number} amount 0..1 9 | */ 10 | export default function contrast (amount = 1) { 11 | const C = toFloatString(parseParamNumber(amount)); 12 | 13 | return shader(` 14 | outColor = pixelColor * ${C}; 15 | `); 16 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/gamma.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | /* 8 | * @param {Number} amount -1..1 , value < 0 is darken, value > 0 is brighten 9 | */ 10 | export default function gamma (amount = 1) { 11 | const C = toFloatString( parseParamNumber(amount) ) 12 | 13 | return shader(` 14 | outColor = vec4(pow(pixelColor.r, ${C}), pow(pixelColor.g, ${C}), pow(pixelColor.b, ${C}), pixelColor.a ); 15 | `); 16 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/gradient.js: -------------------------------------------------------------------------------- 1 | import Color from '../../../Color' 2 | import { 3 | shader, 4 | colorToVec4, 5 | toFloatString 6 | } from '../util' 7 | /** 8 | * F.gradient('red', 'blue', 'yellow', 'white', 10) 9 | * F.gradient('red, blue, yellow, white, 10') 10 | */ 11 | export default function gradient () { 12 | // 전체 매개변수 기준으로 파싱 13 | // 색이 아닌 것 기준으로 scale 변수로 인식 14 | 15 | let params = [...arguments]; 16 | 17 | if (params.length === 1 && typeof params[0] === 'string') { 18 | params = Color.convertMatchesArray(params[0]) 19 | } 20 | 21 | params = params.map(arg => { 22 | return arg 23 | }).join(', ') 24 | 25 | let colors = Color.parseGradient(params); 26 | 27 | colors[0][1] = 0; 28 | colors[colors.length-1][1] = 1; 29 | 30 | colors = colors.map(c => { 31 | const {r, g, b, a} = Color.parse(c[0]) 32 | return [{r, g, b, a}, c[1]]; 33 | }) 34 | 35 | let temp = [] 36 | 37 | for(var i = 0, len = colors.length; i < len - 1; i++) { 38 | const start = colors[i]; 39 | const end = colors[i+1]; 40 | 41 | const startColor = colorToVec4(start[0]) 42 | const endColor = colorToVec4(end[0]) 43 | 44 | const startRate = toFloatString (start[1]); 45 | const endRate = toFloatString (end[1]); 46 | 47 | temp.push(` 48 | if (${startRate} <= rate && rate < ${endRate}) { 49 | outColor = mix(${startColor}, ${endColor}, (rate - ${startRate})/(${endRate} - ${startRate})); 50 | } 51 | `) 52 | } 53 | 54 | return shader(` 55 | float rate = (pixelColor.r * 0.2126 + pixelColor.g * 0.7152 + pixelColor.b * 0.0722); 56 | 57 | ${temp.join('\n')} 58 | `) 59 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/grayscale.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber 3 | } from '../util' 4 | 5 | import matrix from './matrix' 6 | 7 | /** 8 | * 9 | * @param {Number} amount 0..1 10 | */ 11 | export default function grayscale (amount = 1) { 12 | let C = parseParamNumber(amount); 13 | 14 | if (C > 1) C = 1; 15 | 16 | return matrix( 17 | (0.2126 + 0.7874 * (1 - C)), (0.7152 - 0.7152 * (1 - C)), (0.0722 - 0.0722 * (1 - C)), 0, 18 | (0.2126 - 0.2126 * (1 - C)), (0.7152 + 0.2848 * (1 - C)), (0.0722 - 0.0722 * (1 - C)), 0, 19 | (0.2126 - 0.2126 * (1 - C)), (0.7152 - 0.7152 * (1 - C)), (0.0722 + 0.9278 * (1 - C)), 0, 20 | 0, 0, 0, 1 21 | ); 22 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/hue.js: -------------------------------------------------------------------------------- 1 | //http://lolengine.net/blog/2013/07/27/rgb-to-hsv-in-glsl 2 | import { 3 | shader, 4 | parseParamNumber, 5 | toFloatString 6 | } from '../util' 7 | 8 | /* 9 | * @param {Number} amount 0..1 , (real value 0..360) 10 | */ 11 | export default function hue (amount = 1) { 12 | const C = toFloatString( parseParamNumber(amount)) 13 | 14 | return shader(` 15 | vec3 hsv = rgb2hsv(pixelColor.rgb); 16 | hsv.x += ${C}; 17 | outColor = vec4(hsv2rgb(hsv).rgb, pixelColor.a); 18 | `); 19 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/index.js: -------------------------------------------------------------------------------- 1 | 2 | import bitonal from './bitonal' 3 | import brightness from './brightness' 4 | import brownie from './brownie' 5 | import clip from './clip' 6 | import chaos from './chaos' 7 | import contrast from './contrast' 8 | import gamma from './gamma' 9 | import gradient from './gradient' 10 | import grayscale from './grayscale' 11 | import hue from './hue' 12 | import invert from './invert' 13 | import kodachrome from './kodachrome' 14 | import matrix from './matrix' 15 | import noise from './noise' 16 | import opacity from './opacity' 17 | import polaroid from './polaroid' 18 | import saturation from './saturation' 19 | import sepia from './sepia' 20 | import shade from './shade' 21 | import shift from './shift' 22 | import solarize from './solarize' 23 | import technicolor from './technicolor' 24 | import threshold from './threshold' 25 | import thresholdColor from './threshold-color' 26 | import tint from './tint' 27 | 28 | export default { 29 | bitonal, 30 | brightness, 31 | brownie, 32 | clip, 33 | chaos, 34 | contrast, 35 | gamma, 36 | gradient, 37 | grayscale, 38 | hue, 39 | invert, 40 | kodachrome, 41 | matrix, 42 | noise, 43 | opacity, 44 | polaroid, 45 | saturation, 46 | sepia, 47 | shade, 48 | shift, 49 | solarize, 50 | technicolor, 51 | threshold, 52 | 'threshold-color': thresholdColor, 53 | tint 54 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/invert.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | export default function invert (amount = 1) { 8 | const C = toFloatString( parseParamNumber(amount) ); 9 | 10 | return shader(` 11 | outColor = vec4( 12 | (1.0 - pixelColor.r) * ${C}, 13 | (1.0 - pixelColor.g) * ${C}, 14 | (1.0 - pixelColor.b) * ${C}, 15 | pixelColor.a 16 | ); 17 | `); 18 | } 19 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/kodachrome.js: -------------------------------------------------------------------------------- 1 | import matrix from './matrix' 2 | 3 | export default function kodachrome () { 4 | 5 | return matrix( 6 | 1.1285582396593525,-0.3967382283601348,-0.03992559172921793,0, 7 | -0.16404339962244616,1.0835251566291304,-0.05498805115633132,0, 8 | -0.16786010706155763,-0.5603416277695248,1.6014850761964943,0, 9 | 0,0,0,1 10 | ) 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/matrix.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | toFloatString 4 | } from '../util' 5 | 6 | export default function matrix ( 7 | $a = 0, $b = 0, $c = 0, $d = 0, 8 | $e = 0, $f = 0, $g = 0, $h = 0, 9 | $i = 0, $j = 0, $k = 0, $l = 0, 10 | $m = 0, $n = 0, $o = 0, $p = 0 11 | ) { 12 | 13 | const matrix = [ 14 | $a, $b, $c, $d, 15 | $e, $f, $g, $h, 16 | $i, $j, $k, $l, 17 | $m, $n, $o, $p 18 | ].map(toFloatString) 19 | 20 | return shader(` 21 | 22 | outColor = vec4( 23 | ${matrix[0]} * pixelColor.r + ${matrix[1]} * pixelColor.g + ${matrix[2]} * pixelColor.b + ${matrix[3]} * pixelColor.a, 24 | ${matrix[4]} * pixelColor.r + ${matrix[5]} * pixelColor.g + ${matrix[6]} * pixelColor.b + ${matrix[7]} * pixelColor.a, 25 | ${matrix[8]} * pixelColor.r + ${matrix[9]} * pixelColor.g + ${matrix[10]} * pixelColor.b + ${matrix[11]} * pixelColor.a, 26 | ${matrix[12]} * pixelColor.r + ${matrix[13]} * pixelColor.g + ${matrix[14]} * pixelColor.b + ${matrix[15]} * pixelColor.a 27 | ); 28 | `); 29 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/noise.js: -------------------------------------------------------------------------------- 1 | import { shader, parseParamNumber, toFloatString } from '../util'; 2 | 3 | 4 | /** 5 | * 6 | * @param {Number} amount 0..1 7 | */ 8 | export default function noise (amount = 1) { 9 | 10 | const C = Math.abs( parseParamNumber(amount)) 11 | const min = toFloatString( -C ) 12 | const max = toFloatString( C ) 13 | return shader(` 14 | float rnd = ${min} + random( pixelColor.st ) * (${max} - ${min}); 15 | 16 | outColor = vec4(pixelColor.rgb + rnd, 1.0); 17 | `); 18 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/opacity.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | /** 8 | * 9 | * @param {Number} amount 0..1 10 | */ 11 | export default function opacity (amount = 1) { 12 | const C = toFloatString( parseParamNumber(amount)); 13 | 14 | return shader(` 15 | outColor = vec4(pixelColor.rgb, pixelColor.a * ${C}); 16 | `); 17 | } 18 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/polaroid.js: -------------------------------------------------------------------------------- 1 | import matrix from './matrix' 2 | 3 | export default function polaroid () { 4 | 5 | return matrix( 6 | 1.438,-0.062,-0.062,0, 7 | -0.122,1.378,-0.122,0, 8 | -0.016,-0.016,1.483,0, 9 | 0,0,0,1 10 | ) 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/saturation.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber 3 | } from '../util' 4 | import matrix from './matrix' 5 | 6 | 7 | /* 8 | * @param {Number} amount 0..1 9 | */ 10 | export default function saturation (amount = 0) { 11 | const L = 1 - Math.abs(parseParamNumber(amount)); 12 | 13 | return matrix( 14 | L, 0, 0, 0, 15 | 0, L, 0, 0, 16 | 0, 0, L, 0, 17 | 0, 0, 0, L 18 | ) 19 | 20 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/sepia.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber 3 | } from '../util'; 4 | import matrix from "./matrix"; 5 | 6 | /* 7 | * @param {Number} amount 0..100 8 | */ 9 | export default function sepia (amount = 1) { 10 | let C = parseParamNumber(amount); 11 | if (C > 1) C = 1; 12 | 13 | return matrix( 14 | (0.393 + 0.607 * (1 - C)), (0.769 - 0.769 * (1 - C)), (0.189 - 0.189 * (1 - C)), 0, 15 | (0.349 - 0.349 * (1 - C)), (0.686 + 0.314 * (1 - C)), (0.168 - 0.168 * (1 - C)), 0, 16 | (0.272 - 0.272 * (1 - C)), (0.534 - 0.534 * (1 - C)), (0.131 + 0.869 * (1 - C)), 0, 17 | 0, 0, 0, 1 18 | ) 19 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/shade.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | export default function shade(redValue = 1, greenValue = 1, blueValue = 1) { 8 | const r = toFloatString(parseParamNumber(redValue) / 255) 9 | const g = toFloatString(parseParamNumber(greenValue) /255) 10 | const b = toFloatString(parseParamNumber(blueValue) /255) 11 | 12 | return shader(` 13 | outColor = vec4( 14 | pixelColor.r * ${r}, 15 | pixelColor.g * ${g}, 16 | pixelColor.b * ${b}, 17 | pixelColor.a 18 | ); 19 | `); 20 | } 21 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/shift.js: -------------------------------------------------------------------------------- 1 | import matrix from './matrix' 2 | 3 | export default function shift () { 4 | 5 | return matrix( 6 | 1.438,-0.062,-0.062,0, 7 | -0.122,1.378,-0.122,0, 8 | -0.016,-0.016,1.483,0, 9 | 0,0,0,1 10 | ); 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/solarize.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber, 4 | toFloatString 5 | } from '../util' 6 | 7 | export default function solarize (redValue, greenValue, blueValue) { 8 | const r = toFloatString( parseParamNumber(redValue) ) 9 | const g = toFloatString( parseParamNumber(greenValue) ) 10 | const b = toFloatString( parseParamNumber(blueValue) ) 11 | 12 | return shader(` 13 | outColor = vec4( 14 | (pixelColor.r < ${r}) ? 1.0 - pixelColor.r: pixelColor.r, 15 | (pixelColor.g < ${g}) ? 1.0 - pixelColor.g: pixelColor.g, 16 | (pixelColor.b < ${b}) ? 1.0 - pixelColor.b: pixelColor.b, 17 | pixelColor.a 18 | ); 19 | `); 20 | } 21 | 22 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/technicolor.js: -------------------------------------------------------------------------------- 1 | import matrix from './matrix' 2 | 3 | export default function technicolor () { 4 | 5 | return matrix( 6 | 1.9125277891456083,-0.8545344976951645,-0.09155508482755585,0, 7 | -0.3087833385928097,1.7658908555458428,-0.10601743074722245,0, 8 | -0.231103377548616,-0.7501899197440212,1.847597816108189,0, 9 | 0,0,0,1 10 | ) 11 | } -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/threshold-color.js: -------------------------------------------------------------------------------- 1 | import { 2 | parseParamNumber, 3 | shader, 4 | toFloatString 5 | } from '../util' 6 | 7 | export default function thresholdColor (scale = 1) { 8 | scale = toFloatString( parseParamNumber(scale) ) 9 | 10 | return shader(` 11 | float c = ( (pixelColor.r * 0.2126 + pixelColor.g * 0.7152 + pixelColor.b * 0.0722) ) >= ${scale} ? 1.0 : 0.0; 12 | 13 | outColor = vec4(c, c, c, pixelColor.a); 14 | `) 15 | } 16 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/threshold.js: -------------------------------------------------------------------------------- 1 | import thresholdColor from './threshold-color' 2 | /* 3 | * @param {Number} amount 0..100 4 | */ 5 | export default function threshold (scale = 200, amount = 100) { 6 | return thresholdColor(scale, amount, false) 7 | } 8 | -------------------------------------------------------------------------------- /src/util/gl/filter/pixel/tint.js: -------------------------------------------------------------------------------- 1 | import { 2 | shader, 3 | parseParamNumber 4 | } from '../util' 5 | 6 | /** 7 | * 8 | * @param {*} redTint 0..1 9 | * @param {*} greenTint 0..1 10 | * @param {*} blueTint 0..1 11 | */ 12 | export default function (redTint = 0, greenTint = 0, blueTint = 0) { 13 | const r = parseParamNumber(redTint) 14 | const g = parseParamNumber(greenTint) 15 | const b = parseParamNumber(blueTint) 16 | 17 | return shader(` 18 | outColor = vec4( 19 | pixelColor.r += (1 - pixelColor.r) * ${r}, 20 | pixelColor.g += (1 - pixelColor.g) * ${g}, 21 | pixelColor.b += (1 - pixelColor.b) * ${b}, 22 | pixelColor.a 23 | ); 24 | `); 25 | } 26 | -------------------------------------------------------------------------------- /src/util/index.js: -------------------------------------------------------------------------------- 1 | import Color from './Color' 2 | import HueColor from './HueColor' 3 | import ColorNames from './ColorNames' 4 | import ImageFilter from './ImageFilter' 5 | import GL from './GL' 6 | import Canvas from './Canvas' 7 | import ImageLoader from './ImageLoader' 8 | 9 | export default { 10 | Color, 11 | HueColor, 12 | ColorNames, 13 | ImageFilter, 14 | GL, 15 | Canvas, 16 | ImageLoader 17 | } -------------------------------------------------------------------------------- /test/util.Blend.spec.js: -------------------------------------------------------------------------------- 1 | import Blender from '../src/util/Blender' 2 | import Color from '../src/util/Color' 3 | 4 | test('Blend - normal', () => { 5 | const back = Color.parse('#255050'); 6 | const source = Color.parse('#2550ff'); 7 | 8 | var rgb = Blender.normal(back, source); 9 | 10 | expect(rgb).toEqual({ r : 0x25, g : 0x50, b: 0xff, a : 1 }); 11 | 12 | rgb = Blender.multiply(back, source); 13 | 14 | console.log(rgb); 15 | }); 16 | -------------------------------------------------------------------------------- /test/util.Filter.spec.js: -------------------------------------------------------------------------------- 1 | import Filter from '../src/util/Filter' 2 | import Color from '../src/util/Color' 3 | 4 | test('gray filter', () => { 5 | const colorCode = Color.parse('#255050'); 6 | 7 | let testData = [colorCode.r, colorCode.g, colorCode.b]; 8 | 9 | Filter.grayscale(testData); 10 | 11 | expect(testData).toEqual([ 71, 71, 71 ]); 12 | }); 13 | -------------------------------------------------------------------------------- /test/util.ImageFilter.spec.js: -------------------------------------------------------------------------------- 1 | import ImageFilter from '../src/util/ImageFilter' 2 | import Color from '../src/util/Color' 3 | 4 | test('image gray filter', () => { 5 | const colorCode = Color.parse('#255050'); 6 | 7 | const buffer = [ 8 | colorCode.r, colorCode.g, colorCode.b, 255 9 | ] 10 | 11 | const filter = ImageFilter.grayscale(); 12 | 13 | var rgb = filter(buffer); 14 | 15 | expect(rgb).toEqual([ 71, 71, 71, 255]); 16 | }); 17 | --------------------------------------------------------------------------------