Merge pull request #160 from lokesh/dev
chore: Merging dev into master for minor release v2.1
17
.editorconfig
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
# EditorConfig helps developers define and maintain consistent
|
||||||
|
# coding styles between different editors and IDEs
|
||||||
|
# editorconfig.org
|
||||||
|
|
||||||
|
root = true
|
||||||
|
|
||||||
|
[*]
|
||||||
|
|
||||||
|
# Change these settings to your own preference
|
||||||
|
indent_style = space
|
||||||
|
indent_size = 4
|
||||||
|
|
||||||
|
# We recommend you to keep these unchanged
|
||||||
|
end_of_line = lf
|
||||||
|
charset = utf-8
|
||||||
|
trim_trailing_whitespace = true
|
||||||
|
insert_final_newline = true
|
||||||
19
.eslintrc.js
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
module.exports = {
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"commonjs": true,
|
||||||
|
"es6": true,
|
||||||
|
"node": true
|
||||||
|
},
|
||||||
|
"extends": "eslint:recommended",
|
||||||
|
"globals": {
|
||||||
|
"Atomics": "readonly",
|
||||||
|
"SharedArrayBuffer": "readonly"
|
||||||
|
},
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 2018
|
||||||
|
},
|
||||||
|
"rules": {
|
||||||
|
"one-var": ["warn", { "initialized": "never" }]
|
||||||
|
}
|
||||||
|
}
|
||||||
75
.jscsrc
@@ -1,75 +0,0 @@
|
|||||||
{
|
|
||||||
"requireSpaceAfterLineComment": true,
|
|
||||||
"requireSpaceAfterKeywords": [
|
|
||||||
"do",
|
|
||||||
"for",
|
|
||||||
"if",
|
|
||||||
"else",
|
|
||||||
"switch",
|
|
||||||
"case",
|
|
||||||
"try",
|
|
||||||
"catch",
|
|
||||||
"void",
|
|
||||||
"while",
|
|
||||||
"with",
|
|
||||||
"return",
|
|
||||||
"typeof"
|
|
||||||
],
|
|
||||||
"requireSpaceBeforeBlockStatements": true,
|
|
||||||
"requireParenthesesAroundIIFE": true,
|
|
||||||
"requireSpacesInConditionalExpression": true,
|
|
||||||
"disallowMultipleVarDecl": true,
|
|
||||||
"requireBlocksOnNewline": true,
|
|
||||||
"disallowEmptyBlocks": true,
|
|
||||||
"disallowSpacesInsideParentheses": true,
|
|
||||||
"disallowSpaceAfterObjectKeys": true,
|
|
||||||
"requireSpaceBeforeObjectValues": true,
|
|
||||||
"requireCommaBeforeLineBreak": true,
|
|
||||||
"requireOperatorBeforeLineBreak": [
|
|
||||||
"?",
|
|
||||||
"=",
|
|
||||||
"+",
|
|
||||||
"-",
|
|
||||||
"/",
|
|
||||||
"*",
|
|
||||||
"==",
|
|
||||||
"===",
|
|
||||||
"!=",
|
|
||||||
"!==",
|
|
||||||
">",
|
|
||||||
">=",
|
|
||||||
"<",
|
|
||||||
"<="
|
|
||||||
],
|
|
||||||
"disallowSpaceAfterPrefixUnaryOperators": ["++", "--", "+", "-", "~", "!"],
|
|
||||||
"disallowSpaceBeforePostfixUnaryOperators": ["++", "--"],
|
|
||||||
"requireSpaceBeforeBinaryOperators": [
|
|
||||||
"=",
|
|
||||||
"+",
|
|
||||||
"-",
|
|
||||||
"/",
|
|
||||||
"*",
|
|
||||||
"==",
|
|
||||||
"===",
|
|
||||||
"!=",
|
|
||||||
"!=="
|
|
||||||
],
|
|
||||||
"requireSpaceAfterBinaryOperators": [
|
|
||||||
"=",
|
|
||||||
",",
|
|
||||||
"+",
|
|
||||||
"-",
|
|
||||||
"/",
|
|
||||||
"*",
|
|
||||||
"==",
|
|
||||||
"===",
|
|
||||||
"!=",
|
|
||||||
"!=="
|
|
||||||
],
|
|
||||||
"disallowMixedSpacesAndTabs" : true,
|
|
||||||
"disallowTrailingWhitespace": true,
|
|
||||||
"disallowTrailingComma": true,
|
|
||||||
"requireLineFeedAtFileEnd": true,
|
|
||||||
"requireCapitalizedConstructors": true
|
|
||||||
}
|
|
||||||
|
|
||||||
35
.jshintrc
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
"bitwise":true,
|
|
||||||
"browser":true,
|
|
||||||
"camelcase":true,
|
|
||||||
"curly":true,
|
|
||||||
"eqeqeq":true,
|
|
||||||
"forin":true,
|
|
||||||
"freeze":true,
|
|
||||||
"indent":2,
|
|
||||||
"latedef":true,
|
|
||||||
"maxdepth": 6,
|
|
||||||
"maxparams": 6,
|
|
||||||
"maxstatements": 50,
|
|
||||||
"newcap": true,
|
|
||||||
"noarg":true,
|
|
||||||
"noempty":true,
|
|
||||||
"nonbsp":true,
|
|
||||||
"nonew":true,
|
|
||||||
"quotmark":"single",
|
|
||||||
"trailing":true,
|
|
||||||
"undef":true,
|
|
||||||
"unused":"vars",
|
|
||||||
"immed":true,
|
|
||||||
"browser": true,
|
|
||||||
"jquery":true,
|
|
||||||
"predef": [
|
|
||||||
"alert",
|
|
||||||
"confirm",
|
|
||||||
"console",
|
|
||||||
"escape",
|
|
||||||
"define",
|
|
||||||
"module",
|
|
||||||
"require"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
18
CONTRIBUTING.md
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
## Running tests
|
||||||
|
|
||||||
|
Run Cypress integration tests in Chrome browser.
|
||||||
|
|
||||||
|
- `npm run dev` to start local server.
|
||||||
|
- `npm run test`
|
||||||
|
|
||||||
|
## Adding tests
|
||||||
|
|
||||||
|
- Update `cypress/test-pages/index.html` as needed or create a new test page if you need new examples.
|
||||||
|
- Add new tests in `cypress/integration/apis_spec.js`
|
||||||
|
|
||||||
|
## Making a new release
|
||||||
|
|
||||||
|
- Update version number in `src/color-thief.js` and `package.json`
|
||||||
|
- Run `npm run build`
|
||||||
|
- Push to Github repo
|
||||||
|
- Create a new Github release along with tag. Naming convention for both ```v2.8.1```
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
## How to make a release and deploy
|
|
||||||
|
|
||||||
- Update version number in `src/color-thief.js` and `package.json`
|
|
||||||
- Run `grunt build`
|
|
||||||
- Push to Github repo
|
|
||||||
- Create a new Github release along with tag. Naming convention for both ```v2.8.1```
|
|
||||||
50
Gruntfile.js
@@ -1,50 +0,0 @@
|
|||||||
module.exports = function(grunt) {
|
|
||||||
|
|
||||||
grunt.initConfig({
|
|
||||||
connect: {
|
|
||||||
server: {
|
|
||||||
options: {
|
|
||||||
port: 8000
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
jshint: {
|
|
||||||
files: ['src/color-thief.js']
|
|
||||||
},
|
|
||||||
jscs: {
|
|
||||||
src: [
|
|
||||||
'src/color-thief.js'
|
|
||||||
],
|
|
||||||
options: {
|
|
||||||
config: ".jscsrc"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
uglify: {
|
|
||||||
options: {
|
|
||||||
preserveComments: 'some',
|
|
||||||
sourceMap: false
|
|
||||||
},
|
|
||||||
dist: {
|
|
||||||
files: {
|
|
||||||
'dist/color-thief.min.js': ['src/color-thief.js']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
watch: {
|
|
||||||
test: {
|
|
||||||
files: ['src/color-thief.js'],
|
|
||||||
tasks: ['jshint', 'jscs']
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-connect');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-jshint');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-uglify');
|
|
||||||
grunt.loadNpmTasks('grunt-contrib-watch');
|
|
||||||
grunt.loadNpmTasks('grunt-jscs');
|
|
||||||
|
|
||||||
grunt.registerTask('default', ['connect', 'watch']);
|
|
||||||
grunt.registerTask('test', ['jshint', 'jscs']);
|
|
||||||
grunt.registerTask('build', ['uglify']);
|
|
||||||
};
|
|
||||||
17
README.md
@@ -8,16 +8,12 @@ A script for grabbing the color palette from an image. Uses Javascript and the c
|
|||||||
## How to use
|
## How to use
|
||||||
|
|
||||||
### Get the dominant color from an image
|
### Get the dominant color from an image
|
||||||
|
|
||||||
```js
|
```js
|
||||||
var colorThief = new ColorThief();
|
var colorThief = new ColorThief();
|
||||||
colorThief.getColor(sourceImage);
|
colorThief.getColor(sourceImage);
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
|
||||||
getColor(sourceImage[, quality])
|
|
||||||
returns [num, num, num]
|
|
||||||
```
|
|
||||||
|
|
||||||
### Build a color palette from an image
|
### Build a color palette from an image
|
||||||
|
|
||||||
In this example, we build an 8 color palette.
|
In this example, we build an 8 color palette.
|
||||||
@@ -27,7 +23,10 @@ var colorThief = new ColorThief();
|
|||||||
colorThief.getPalette(sourceImage, 8);
|
colorThief.getPalette(sourceImage, 8);
|
||||||
```
|
```
|
||||||
|
|
||||||
```js
|
### API
|
||||||
getPalette(sourceImage[, colorCount, quality])
|
|
||||||
returns [ [num, num, num], [num, num, num], ... ]
|
|
||||||
```
|
| Method | Return | Description |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `getColor(image [, quality])` | `[Number, Number, Number]` | WIP |
|
||||||
|
| `getPalette(image [, colorCount, quality]` | `[[Number, Number, Number], ...]` | WIP |
|
||||||
|
|||||||
26
bower.json
@@ -1,26 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "color-thief",
|
|
||||||
"homepage": "http://lokeshdhakar.com/projects/color-thief/",
|
|
||||||
"authors": [
|
|
||||||
"Lokesh Dhakar"
|
|
||||||
],
|
|
||||||
"description": "Grab the dominant color or color palette from an image.",
|
|
||||||
"main": "src/color-thief.js",
|
|
||||||
"keywords": [
|
|
||||||
"color",
|
|
||||||
"palette",
|
|
||||||
"sampling",
|
|
||||||
"image",
|
|
||||||
"picture",
|
|
||||||
"photo",
|
|
||||||
"canvas"
|
|
||||||
],
|
|
||||||
"license": "MIT",
|
|
||||||
"ignore": [
|
|
||||||
"**/.*",
|
|
||||||
"node_modules",
|
|
||||||
"bower_components",
|
|
||||||
"test",
|
|
||||||
"tests"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
20
build/build.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
const minify = require('@node-minify/core');
|
||||||
|
const uglify = require('@node-minify/uglify-es');
|
||||||
|
|
||||||
|
minify({
|
||||||
|
compressor: uglify,
|
||||||
|
input: './src/color-thief.js',
|
||||||
|
output: './dist/color-thief.min.js',
|
||||||
|
options: {
|
||||||
|
output: {
|
||||||
|
comments: 'some'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
callback: function(err, min) {
|
||||||
|
if (err) {
|
||||||
|
console.log('⚠️ERROR:' + err);
|
||||||
|
} else {
|
||||||
|
console.log('✅ Minification completed');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
1
cypress.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
5
cypress/fixtures/example.json
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"name": "Using fixtures to represent data",
|
||||||
|
"email": "hello@cypress.io",
|
||||||
|
"body": "Fixtures are a great way to mock data for responses to routes"
|
||||||
|
}
|
||||||
73
cypress/integration/api_spec.js
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
function rgbCount(text) {
|
||||||
|
const vals = text.split(',');
|
||||||
|
for (const val of vals) {
|
||||||
|
if (val < 0 || val > 255) {
|
||||||
|
throw 'Invalid RGB color value';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return vals.length / 3
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getColor()', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
cy.visit('http://localhost:8080/cypress/test-pages/index.html');
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns valid color from black image', function() {
|
||||||
|
cy.get('[data-image="black.png"] .output-color').should(($el) => {
|
||||||
|
const count = rgbCount($el.text())
|
||||||
|
expect(count).to.equal(1);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns valid color from red image', function() {
|
||||||
|
cy.get('[data-image="red.png"] .output-color').should(($el) => {
|
||||||
|
const count = rgbCount($el.text())
|
||||||
|
expect(count).to.equal(1);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
it('returns valid color from rainbow image', function() {
|
||||||
|
cy.get('[data-image="rainbow-horizontal.png"] .output-color').should(($el) => {
|
||||||
|
const count = rgbCount($el.text())
|
||||||
|
expect(count).to.equal(1);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
|
||||||
|
// ⚠️BREAKS
|
||||||
|
// it('returns valid color from white image', function() {
|
||||||
|
// cy.get('[data-image="white.png"] .output-color').should(($el) => {
|
||||||
|
// const count = rgbCount($el.text())
|
||||||
|
// expect(count).to.equal(1);
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
|
||||||
|
// ⚠️BREAKS
|
||||||
|
// it('returns valid color from transparent image', function() {
|
||||||
|
// cy.get('[data-image="transparent.png"] .output-color').should(($el) => {
|
||||||
|
// const count = rgbCount($el.text())
|
||||||
|
// expect(count).to.equal(1);
|
||||||
|
// });
|
||||||
|
// })
|
||||||
|
})
|
||||||
|
|
||||||
|
function testPaletteCount(num) {
|
||||||
|
it(`returns ${num} color when colorCount set to ${num}`, function() {
|
||||||
|
cy.get(`[data-image="rainbow-horizontal.png"] .palette[data-count="${num}"] .output-palette`).should(($el) => {
|
||||||
|
const count = rgbCount($el.text())
|
||||||
|
expect(count).to.equal(num);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
describe('getPalette()', function() {
|
||||||
|
beforeEach(function() {
|
||||||
|
cy.visit('http://localhost:8080/cypress/test-pages/index.html');
|
||||||
|
})
|
||||||
|
|
||||||
|
// FULL TEST LIST = [1, 2, 3, 5, 7, 10, 20];
|
||||||
|
|
||||||
|
// Non-breaking tests
|
||||||
|
let testCounts = [5, 7];
|
||||||
|
testCounts.forEach((count) => testPaletteCount(count))
|
||||||
|
})
|
||||||
17
cypress/plugins/index.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example plugins/index.js can be used to load plugins
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off loading
|
||||||
|
// the plugins file with the 'pluginsFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/plugins-guide
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// This function is called when a project is opened or re-opened (e.g. due to
|
||||||
|
// the project's config changing)
|
||||||
|
|
||||||
|
module.exports = (on, config) => {
|
||||||
|
// `on` is used to hook into various events Cypress emits
|
||||||
|
// `config` is the resolved Cypress config
|
||||||
|
}
|
||||||
25
cypress/support/commands.js
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
// ***********************************************
|
||||||
|
// This example commands.js shows you how to
|
||||||
|
// create various custom commands and overwrite
|
||||||
|
// existing commands.
|
||||||
|
//
|
||||||
|
// For more comprehensive examples of custom
|
||||||
|
// commands please read more here:
|
||||||
|
// https://on.cypress.io/custom-commands
|
||||||
|
// ***********************************************
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a parent command --
|
||||||
|
// Cypress.Commands.add("login", (email, password) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a child command --
|
||||||
|
// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is a dual command --
|
||||||
|
// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... })
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// -- This is will overwrite an existing command --
|
||||||
|
// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... })
|
||||||
20
cypress/support/index.js
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
// ***********************************************************
|
||||||
|
// This example support/index.js is processed and
|
||||||
|
// loaded automatically before your test files.
|
||||||
|
//
|
||||||
|
// This is a great place to put global configuration and
|
||||||
|
// behavior that modifies Cypress.
|
||||||
|
//
|
||||||
|
// You can change the location of this file or turn off
|
||||||
|
// automatically serving support files with the
|
||||||
|
// 'supportFile' configuration option.
|
||||||
|
//
|
||||||
|
// You can read more here:
|
||||||
|
// https://on.cypress.io/configuration
|
||||||
|
// ***********************************************************
|
||||||
|
|
||||||
|
// Import commands.js using ES2015 syntax:
|
||||||
|
import './commands'
|
||||||
|
|
||||||
|
// Alternatively you can use CommonJS syntax:
|
||||||
|
// require('./commands')
|
||||||
BIN
cypress/test-pages/img/black.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
cypress/test-pages/img/rainbow-horizontal.png
Normal file
|
After Width: | Height: | Size: 42 KiB |
BIN
cypress/test-pages/img/rainbow-vertical.png
Normal file
|
After Width: | Height: | Size: 138 KiB |
BIN
cypress/test-pages/img/red.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
cypress/test-pages/img/transparent.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
cypress/test-pages/img/white.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
57
cypress/test-pages/index.html
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<title>Color Thief</title>
|
||||||
|
<link rel="stylesheet" href="./screen.css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<div id="example-images"></div>
|
||||||
|
|
||||||
|
<script id='image-tpl' type='text/x-mustache'>
|
||||||
|
{{#.}}
|
||||||
|
<div class="image-section" data-image="{{.}}">
|
||||||
|
<h2>{{.}}</h2>
|
||||||
|
<img class="image" src="./img/{{.}}" />
|
||||||
|
<div class="output"></div>
|
||||||
|
</div>
|
||||||
|
{{/.}}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="color-tpl" type="text/x-mustache">
|
||||||
|
<div class="color">
|
||||||
|
<h3>getColor(img)</h3>
|
||||||
|
<div class="swatches">
|
||||||
|
<div class="swatch" style="background-color: rgb({{color.0}}, {{color.1}}, {{color.2}})"></div>
|
||||||
|
</div>
|
||||||
|
<code>
|
||||||
|
<div class="output-color">{{colorStr}}</div>
|
||||||
|
<div class="time">{{elapsedTime}}ms</div>
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<script id="palette-tpl" type="text/x-mustache">
|
||||||
|
<div class="palette" data-count="{{count}}">
|
||||||
|
<h3>getPalette(img, {{count}})</h3>
|
||||||
|
<div class="swatches">
|
||||||
|
{{#palette}}
|
||||||
|
<div class="swatch" style="background-color: rgb({{0}}, {{1}}, {{2}})"></div>
|
||||||
|
{{/palette}}
|
||||||
|
</div>
|
||||||
|
<code>
|
||||||
|
<div class="output-palette">{{paletteStr}}</div>
|
||||||
|
<div class="time">{{elapsedTime}}ms</div>
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
|
</script>
|
||||||
|
|
||||||
|
|
||||||
|
<script src="/src/color-thief.js"></script>
|
||||||
|
<script src="/node_modules/mustache/mustache.js"></script>
|
||||||
|
<script src="index.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
58
cypress/test-pages/index.js
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
var colorThief = new ColorThief();
|
||||||
|
|
||||||
|
var images = [
|
||||||
|
'black.png',
|
||||||
|
'red.png',
|
||||||
|
'rainbow-horizontal.png',
|
||||||
|
'rainbow-vertical.png',
|
||||||
|
// 'transparent.png',
|
||||||
|
// 'white.png',
|
||||||
|
];
|
||||||
|
|
||||||
|
// Render example images
|
||||||
|
var examplesHTML = Mustache.to_html(document.getElementById('image-tpl').innerHTML, images);
|
||||||
|
document.getElementById('example-images').innerHTML = examplesHTML;
|
||||||
|
|
||||||
|
// Once images are loaded, process them
|
||||||
|
document.querySelectorAll('.image').forEach((image) => {
|
||||||
|
const section = image.closest('.image-section');
|
||||||
|
if (this.complete) {
|
||||||
|
showColorsForImage(image, section);
|
||||||
|
} else {
|
||||||
|
image.addEventListener('load', function() {
|
||||||
|
showColorsForImage(image, section);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Run Color Thief functions and display results below image.
|
||||||
|
// We also log execution time of functions for display.
|
||||||
|
const showColorsForImage = function(image, section) {
|
||||||
|
// getColor(img)
|
||||||
|
let start = Date.now();
|
||||||
|
let result = colorThief.getColor(image);
|
||||||
|
let elapsedTime = Date.now() - start;
|
||||||
|
const colorHTML = Mustache.to_html(document.getElementById('color-tpl').innerHTML, {
|
||||||
|
color: result,
|
||||||
|
colorStr: result.toString(),
|
||||||
|
elapsedTime
|
||||||
|
})
|
||||||
|
|
||||||
|
// getPalette(img)
|
||||||
|
let paletteHTML = '';
|
||||||
|
let colorCounts = [null, 1, 2, 3, 5, 7, 10, 20];
|
||||||
|
colorCounts.forEach((count) => {
|
||||||
|
let start = Date.now();
|
||||||
|
let result = colorThief.getPalette(image, count);
|
||||||
|
let elapsedTime = Date.now() - start;
|
||||||
|
paletteHTML += Mustache.to_html(document.getElementById('palette-tpl').innerHTML, {
|
||||||
|
count,
|
||||||
|
palette: result,
|
||||||
|
paletteStr: result.toString(),
|
||||||
|
elapsedTime
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
|
const outputEl = section.querySelector('.output');
|
||||||
|
outputEl.innerHTML += colorHTML + paletteHTML;
|
||||||
|
};
|
||||||
95
cypress/test-pages/screen.css
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
:root {
|
||||||
|
/* Colors */
|
||||||
|
--color: #000;
|
||||||
|
--bg-color: #f9f9f9;
|
||||||
|
--primary-color: #fc4c02;
|
||||||
|
--secondary-color: #f68727;
|
||||||
|
--muted-color: #999;
|
||||||
|
--code-color: var(--primary-color);
|
||||||
|
--code-bg-color: #fff;
|
||||||
|
|
||||||
|
/* Typography */
|
||||||
|
--font: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||||
|
--code-font: Menlo, Consolas, Monaco, Lucida Console, monospace;
|
||||||
|
--bold: 700;
|
||||||
|
--x-bold: 900;
|
||||||
|
--line-height: 1.5em;
|
||||||
|
--line-height-heading: 1.3em;
|
||||||
|
|
||||||
|
/* Breakpoints */
|
||||||
|
--sm-screen: 640px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Base
|
||||||
|
* *----------------------------------------------- */
|
||||||
|
* {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: var(--bg-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Typography
|
||||||
|
* *----------------------------------------------- */
|
||||||
|
|
||||||
|
html {
|
||||||
|
font-size: 16px;
|
||||||
|
font-family: var(--font);
|
||||||
|
line-height: var(--line-height);
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1,
|
||||||
|
h2,
|
||||||
|
h3 {
|
||||||
|
font-weight: var(--x-bold);
|
||||||
|
line-height: var(--line-height-heading);
|
||||||
|
letter-spacing: -0.005em;
|
||||||
|
}
|
||||||
|
|
||||||
|
h2 {
|
||||||
|
margin: 0 0 0.25em 0;
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
margin: 1em 0 0.25em 0;
|
||||||
|
font-size: 1.06rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
code {
|
||||||
|
font-family: var(--code-font);
|
||||||
|
overflow-wrap: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* -- Layout ------------------------------------------------------------------ */
|
||||||
|
|
||||||
|
.image-section {
|
||||||
|
border-bottom: 1px solid #ccc;
|
||||||
|
padding: 16px 16px 32px 16px;
|
||||||
|
margin-bottom: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.swatch {
|
||||||
|
display: inline-block;
|
||||||
|
background: #dddddd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.color .swatch {
|
||||||
|
width: 6rem;
|
||||||
|
height: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette .swatch {
|
||||||
|
width: 3rem;
|
||||||
|
height: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
color: var(--muted-color);
|
||||||
|
font-weight: normal;
|
||||||
|
}
|
||||||
7
dist/color-thief.min.js
vendored
|
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
|
Before Width: | Height: | Size: 137 KiB After Width: | Height: | Size: 137 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
9111
examples/js/jquery.js
vendored
@@ -1,224 +0,0 @@
|
|||||||
/**! normalize.css v2.1.1 | MIT License | git.io/normalize
|
|
||||||
|
|
||||||
// HTML5 display definitions
|
|
||||||
|
|
||||||
// Correct `block` display not defined in IE 8/9.
|
|
||||||
article, aside, details, figcaption, figure, footer, header, hgroup, main, nav, section, summary
|
|
||||||
display: block
|
|
||||||
|
|
||||||
// Correct `inline-block` display not defined in IE 8/9.
|
|
||||||
audio, canvas, video
|
|
||||||
display: inline-block
|
|
||||||
|
|
||||||
audio:not([controls])
|
|
||||||
// Prevent modern browsers from displaying `audio` without controls.
|
|
||||||
display: none
|
|
||||||
|
|
||||||
// Remove excess height in iOS 5 devices.
|
|
||||||
height: 0
|
|
||||||
|
|
||||||
// Address styling not present in IE 8/9.
|
|
||||||
[hidden]
|
|
||||||
display: none
|
|
||||||
|
|
||||||
|
|
||||||
// Base
|
|
||||||
|
|
||||||
html
|
|
||||||
// Prevent system color scheme's background color being used in Firefox, IE, and Opera.
|
|
||||||
background: #fff
|
|
||||||
|
|
||||||
// Prevent system color scheme's text color being used in Firefox, IE, and Opera.
|
|
||||||
color: #000
|
|
||||||
|
|
||||||
// Set default font family to sans-serif.
|
|
||||||
font-family: sans-serif
|
|
||||||
|
|
||||||
// Prevent iOS text size adjust after orientation change, without disabling user zoom.
|
|
||||||
-ms-text-size-adjust: 100%
|
|
||||||
-webkit-text-size-adjust: 100%
|
|
||||||
|
|
||||||
// Remove default margin.
|
|
||||||
body
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
|
|
||||||
// Links
|
|
||||||
|
|
||||||
a
|
|
||||||
// Address `outline` inconsistency between Chrome and other browsers.
|
|
||||||
&:focus
|
|
||||||
outline: thin dotted
|
|
||||||
|
|
||||||
// Improve readability when focused and also mouse hovered in all browsers.
|
|
||||||
&:active, &:hover
|
|
||||||
outline: 0
|
|
||||||
|
|
||||||
|
|
||||||
// Typography
|
|
||||||
|
|
||||||
// Address variable `h1` font-size and margin within `section` and `article` contexts in Firefox 4+, Safari 5, and Chrome.
|
|
||||||
h1
|
|
||||||
font-size: 2em
|
|
||||||
margin: 0.67em 0
|
|
||||||
|
|
||||||
// Address styling not present in IE 8/9, Safari 5, and Chrome.
|
|
||||||
abbr[title]
|
|
||||||
border-bottom: 1px dotted
|
|
||||||
|
|
||||||
// Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome.
|
|
||||||
b, strong
|
|
||||||
font-weight: bold
|
|
||||||
|
|
||||||
// Address styling not present in Safari 5 and Chrome.
|
|
||||||
dfn
|
|
||||||
font-style: italic
|
|
||||||
|
|
||||||
// Address differences between Firefox and other browsers.
|
|
||||||
hr
|
|
||||||
-moz-box-sizing: content-box
|
|
||||||
box-sizing: content-box
|
|
||||||
height: 0
|
|
||||||
|
|
||||||
// Address styling not present in IE 8/9.
|
|
||||||
mark
|
|
||||||
background: #ff0
|
|
||||||
color: #000
|
|
||||||
|
|
||||||
// Correct font family set oddly in Safari 5 and Chrome.
|
|
||||||
code, kbd, pre, samp
|
|
||||||
font-family: monospace, serif
|
|
||||||
font-size: 1em
|
|
||||||
|
|
||||||
// Improve readability of pre-formatted text in all browsers.
|
|
||||||
pre
|
|
||||||
white-space: pre-wrap
|
|
||||||
|
|
||||||
// Set consistent quote types.
|
|
||||||
q
|
|
||||||
quotes: '\201C' '\201D' '\2018' '\2019'
|
|
||||||
|
|
||||||
// Address inconsistent and variable font size in all browsers.
|
|
||||||
small
|
|
||||||
font-size: 80%
|
|
||||||
|
|
||||||
// Prevent `sub` and `sup` affecting `line-height` in all browsers.
|
|
||||||
sub, sup
|
|
||||||
font-size: 75%
|
|
||||||
line-height: 0
|
|
||||||
position: relative
|
|
||||||
vertical-align: baseline
|
|
||||||
|
|
||||||
sup
|
|
||||||
top: -0.5em
|
|
||||||
|
|
||||||
sub
|
|
||||||
bottom: -0.25em
|
|
||||||
|
|
||||||
|
|
||||||
// Embedded content
|
|
||||||
|
|
||||||
// Remove border when inside `a` element in IE 8/9.
|
|
||||||
img
|
|
||||||
border: 0
|
|
||||||
|
|
||||||
// Correct overflow displayed oddly in IE 9.
|
|
||||||
svg:not(:root)
|
|
||||||
overflow: hidden
|
|
||||||
|
|
||||||
|
|
||||||
// Figures
|
|
||||||
|
|
||||||
// Address margin not present in IE 8/9 and Safari 5.
|
|
||||||
figure
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
|
|
||||||
// Forms
|
|
||||||
|
|
||||||
// Define consistent border, margin, and padding.
|
|
||||||
fieldset
|
|
||||||
border: 1px solid #c0c0c0
|
|
||||||
margin: 0 2px
|
|
||||||
padding: 0.35em 0.625em 0.75em
|
|
||||||
|
|
||||||
legend
|
|
||||||
// Correct `color` not being inherited in IE 8/9.
|
|
||||||
border: 0
|
|
||||||
|
|
||||||
// Remove padding so people aren't caught out if they zero out fieldsets.
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
button, input, select, textarea
|
|
||||||
// Correct font family not being inherited in all browsers.
|
|
||||||
font-family: inherit
|
|
||||||
|
|
||||||
// Correct font size not being inherited in all browsers.
|
|
||||||
font-size: 100%
|
|
||||||
|
|
||||||
// Address margins set differently in Firefox 4+, Safari 5, and Chrome.
|
|
||||||
margin: 0
|
|
||||||
|
|
||||||
// Address Firefox 4+ setting `line-height` on `input` using `!important` in the UA stylesheet.
|
|
||||||
button, input
|
|
||||||
line-height: normal
|
|
||||||
|
|
||||||
// Address inconsistent `text-transform` inheritance for `button` and `select`.
|
|
||||||
// All other form control elements do not inherit `text-transform` values.
|
|
||||||
// Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+.
|
|
||||||
// Correct `select` style inheritance in Firefox 4+ and Opera.
|
|
||||||
button, select
|
|
||||||
text-transform: none
|
|
||||||
|
|
||||||
button, html input[type='button'], input[type='reset'], input[type='submit']
|
|
||||||
// Avoid the WebKit bug in Android 4.0.* where `html input[type='button'] { -webkit-appearance: button }` destroys native `audio` and `video` controls.
|
|
||||||
// Correct inability to style clickable `input` types in iOS.
|
|
||||||
-webkit-appearance: button
|
|
||||||
|
|
||||||
// Improve usability and consistency of cursor style between image-type `input` and others.
|
|
||||||
cursor: pointer
|
|
||||||
|
|
||||||
// Re-set default cursor for disabled elements.
|
|
||||||
button[disabled], html input[disabled]
|
|
||||||
cursor: default
|
|
||||||
|
|
||||||
input
|
|
||||||
&[type='checkbox'], &[type='radio']
|
|
||||||
// Address box sizing set to `content-box` in IE 8/9.
|
|
||||||
box-sizing: border-box
|
|
||||||
|
|
||||||
// Remove excess padding in IE 8/9.
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
&[type='search']
|
|
||||||
// Address `appearance` set to `searchfield` in Safari 5 and Chrome.
|
|
||||||
-webkit-appearance: textfield
|
|
||||||
|
|
||||||
// Address `box-sizing` set to `border-box` in Safari 5 and Chrome (include `-moz` to future-proof).
|
|
||||||
-moz-box-sizing: content-box
|
|
||||||
-webkit-box-sizing: content-box
|
|
||||||
box-sizing: content-box
|
|
||||||
|
|
||||||
// Remove inner padding and search cancel button in Safari 5 and Chrome on OS X.
|
|
||||||
&::-webkit-search-cancel-button, &::-webkit-search-decoration
|
|
||||||
-webkit-appearance: none
|
|
||||||
|
|
||||||
// Remove inner padding and border in Firefox 4+.
|
|
||||||
button::-moz-focus-inner, input::-moz-focus-inner
|
|
||||||
border: 0
|
|
||||||
padding: 0
|
|
||||||
|
|
||||||
textarea
|
|
||||||
// Remove default vertical scrollbar in IE 8/9.
|
|
||||||
overflow: auto
|
|
||||||
|
|
||||||
// Improve readability and alignment in all browsers.
|
|
||||||
vertical-align: top
|
|
||||||
|
|
||||||
|
|
||||||
// Tables
|
|
||||||
|
|
||||||
// Remove most spacing between table cells.
|
|
||||||
table
|
|
||||||
border-collapse: collapse
|
|
||||||
border-spacing: 0
|
|
||||||
@@ -1,405 +0,0 @@
|
|||||||
@import "compass/css3"
|
|
||||||
@import "compass/utilities/general/clearfix"
|
|
||||||
|
|
||||||
@import "normalize"
|
|
||||||
|
|
||||||
// COLORS & BACKGROUNDS --------------------------------------------------------
|
|
||||||
|
|
||||||
$yellow: #fdf485
|
|
||||||
$orange: #e67e39
|
|
||||||
$blue: #4ae
|
|
||||||
$green: #61c227
|
|
||||||
$gray: #777
|
|
||||||
$gray-light: #aaa
|
|
||||||
$gray-dark: #222
|
|
||||||
|
|
||||||
$color: $gray
|
|
||||||
$bg-color: #f3f3f3
|
|
||||||
$border-color: darken($bg-color, 5%)
|
|
||||||
$header-bg-color: #fff
|
|
||||||
$section-heading-color: $orange
|
|
||||||
$heading-color: $gray-dark
|
|
||||||
$link-color: $blue
|
|
||||||
$code-color: $gray-light
|
|
||||||
|
|
||||||
// TYPE --------------------------------------------------------
|
|
||||||
|
|
||||||
$body-font-family: "Karla", "lucida grande", sans-serif
|
|
||||||
$heading-font-family: "Montserrat", "Helvetica", sans-serif
|
|
||||||
$code-font-family: "Karla", "lucida grande", sans-serif
|
|
||||||
|
|
||||||
// LAYOUT --------------------------------------------------------
|
|
||||||
|
|
||||||
$gutter: 30px
|
|
||||||
$max-column-width: 600px
|
|
||||||
|
|
||||||
$sharing-section-z-index: 10
|
|
||||||
|
|
||||||
// UI COMPONENTS --------------------------------------------------------
|
|
||||||
|
|
||||||
$radius: 8px
|
|
||||||
|
|
||||||
|
|
||||||
/* Typography
|
|
||||||
*----------------------------------------------- */
|
|
||||||
|
|
||||||
html
|
|
||||||
font: 87% / 1.5 $body-font-family, sans-serif
|
|
||||||
font-weight: 400
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
html
|
|
||||||
font-size: 100%
|
|
||||||
|
|
||||||
@media (min-width: 64rem)
|
|
||||||
html
|
|
||||||
font-size: 106%
|
|
||||||
|
|
||||||
body
|
|
||||||
color: $color
|
|
||||||
background-color: $bg-color
|
|
||||||
|
|
||||||
h1, h2, h3, h4, h5
|
|
||||||
color: $heading-color
|
|
||||||
line-height: 1.2em
|
|
||||||
font-family: $heading-font-family
|
|
||||||
font-weight: 700
|
|
||||||
|
|
||||||
h1
|
|
||||||
font-size: 4rem
|
|
||||||
margin: 0 0 0.2em 0
|
|
||||||
line-height: 1.1em
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
h1
|
|
||||||
font-size: 4.5rem
|
|
||||||
|
|
||||||
@media (min-width: 64rem)
|
|
||||||
h1
|
|
||||||
font-size: 5rem
|
|
||||||
|
|
||||||
h2
|
|
||||||
color: $section-heading-color
|
|
||||||
margin-bottom: 1.5rem
|
|
||||||
font-size: 1.5rem
|
|
||||||
text-transform: uppercase
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
h2
|
|
||||||
font-size: 2rem
|
|
||||||
|
|
||||||
h3
|
|
||||||
font-size: 1.2rem
|
|
||||||
margin-bottom: .5rem
|
|
||||||
|
|
||||||
p
|
|
||||||
margin: 0 auto 2em auto
|
|
||||||
text-align: left
|
|
||||||
|
|
||||||
.lead
|
|
||||||
max-width: 50rem
|
|
||||||
margin-bottom: 1.4rem
|
|
||||||
font-size: 1.1rem
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
.lead
|
|
||||||
font-size: 1.25rem
|
|
||||||
|
|
||||||
strong
|
|
||||||
font-weight: bold
|
|
||||||
|
|
||||||
a
|
|
||||||
color: $link-color
|
|
||||||
text-decoration: none
|
|
||||||
&:hover
|
|
||||||
text-decoration: underline
|
|
||||||
|
|
||||||
::-moz-selection,
|
|
||||||
::selection
|
|
||||||
background: $orange
|
|
||||||
color: white
|
|
||||||
|
|
||||||
|
|
||||||
/* Code
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
code
|
|
||||||
color: $code-color
|
|
||||||
+border-radius($radius)
|
|
||||||
font-family: Consolas, Courier, monospace
|
|
||||||
font-size: 0.9rem
|
|
||||||
padding: 0.1rem 0.3rem
|
|
||||||
position: relative
|
|
||||||
top: -1px
|
|
||||||
|
|
||||||
|
|
||||||
/* Lists
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
ul
|
|
||||||
margin: 0
|
|
||||||
text-align: left
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
ul
|
|
||||||
display: inline-block
|
|
||||||
|
|
||||||
|
|
||||||
/* Buttons
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
.button
|
|
||||||
display: block
|
|
||||||
padding: 0.7rem 2rem
|
|
||||||
margin-bottom: 0.5rem
|
|
||||||
border: none
|
|
||||||
color: #fff
|
|
||||||
background-color: $link-color
|
|
||||||
font-size: 1.1rem
|
|
||||||
font-weight: bold
|
|
||||||
text-transform: uppercase
|
|
||||||
+border-radius($radius)
|
|
||||||
vertical-align: middle
|
|
||||||
white-space: nowrap
|
|
||||||
&:hover
|
|
||||||
background: darken($link-color, 10%)
|
|
||||||
text-decoration: none
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
.button
|
|
||||||
display: inline-block
|
|
||||||
margin: 0 0.25rem
|
|
||||||
|
|
||||||
.button-minor
|
|
||||||
padding: 0.35rem 1rem
|
|
||||||
border: 2px solid $link-color
|
|
||||||
color: $link-color
|
|
||||||
background-color: transparent
|
|
||||||
font-size: 0.8rem
|
|
||||||
&:hover
|
|
||||||
color: white
|
|
||||||
|
|
||||||
|
|
||||||
/* Elements
|
|
||||||
* ========================================================================== */
|
|
||||||
|
|
||||||
hr
|
|
||||||
border: 0
|
|
||||||
border-top: 2px solid $border-color
|
|
||||||
margin: 2rem auto
|
|
||||||
width: 3rem
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
hr
|
|
||||||
margin: 2.5rem auto
|
|
||||||
|
|
||||||
/* -- Layout ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
*, *:before, *:after
|
|
||||||
+box-sizing("border-box")
|
|
||||||
|
|
||||||
body
|
|
||||||
margin: 0
|
|
||||||
padding: 0
|
|
||||||
background: $bg-color
|
|
||||||
|
|
||||||
section
|
|
||||||
border-top: 2px solid $border-color
|
|
||||||
text-align: center
|
|
||||||
padding: 1.5rem 0
|
|
||||||
&:first-of-type
|
|
||||||
border-top: none
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
section
|
|
||||||
padding: 2rem 0
|
|
||||||
|
|
||||||
.container
|
|
||||||
margin: 0 auto
|
|
||||||
max-width: 40rem
|
|
||||||
width: 90%
|
|
||||||
|
|
||||||
/* -- Header -- */
|
|
||||||
|
|
||||||
header
|
|
||||||
padding: 4rem 0 2rem 0
|
|
||||||
background-color: $header-bg-color
|
|
||||||
text-align: center
|
|
||||||
p
|
|
||||||
text-align: center
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
header
|
|
||||||
padding: 2rem 0
|
|
||||||
|
|
||||||
|
|
||||||
/* -- Examples -- */
|
|
||||||
|
|
||||||
.image-section
|
|
||||||
margin-bottom: 80px
|
|
||||||
.image-wrap
|
|
||||||
position: relative
|
|
||||||
line-height: 1em
|
|
||||||
|
|
||||||
.examples-section
|
|
||||||
.image-section
|
|
||||||
.target-image
|
|
||||||
+border-bottom-radius($radius)
|
|
||||||
.image-section.with-color-thief-output
|
|
||||||
.target-image
|
|
||||||
+border-bottom-radius(0)
|
|
||||||
|
|
||||||
.run-functions-button
|
|
||||||
position: absolute
|
|
||||||
top: 50%
|
|
||||||
left: 50%
|
|
||||||
width: 8rem
|
|
||||||
height: 8rem
|
|
||||||
margin-top: -4rem
|
|
||||||
margin-left: -4rem
|
|
||||||
border: none
|
|
||||||
+border-radius(50%)
|
|
||||||
color: $color
|
|
||||||
background-color: $yellow
|
|
||||||
font-size: 2rem
|
|
||||||
font-weight: bold
|
|
||||||
cursor: pointer
|
|
||||||
text-transform: uppercase
|
|
||||||
outline: none
|
|
||||||
&:hover
|
|
||||||
+scale(1.1)
|
|
||||||
+transition(transform .2s)
|
|
||||||
&:active
|
|
||||||
+scale(0.9)
|
|
||||||
&.hide
|
|
||||||
background-color: $yellow
|
|
||||||
color: $color
|
|
||||||
+transition(transform .6s, top .6s cubic-bezier(0.220, -0.370, 0.750, 0.750))
|
|
||||||
top: 105%
|
|
||||||
+scale(0)
|
|
||||||
|
|
||||||
// Use Modernizr to check for touch support
|
|
||||||
.touch
|
|
||||||
.touch-label
|
|
||||||
display: inline
|
|
||||||
.no-touch-label
|
|
||||||
display: none
|
|
||||||
.no-touch
|
|
||||||
.touch-label
|
|
||||||
display: none
|
|
||||||
.no-touch-label
|
|
||||||
display: inline
|
|
||||||
|
|
||||||
.target-image
|
|
||||||
display: block
|
|
||||||
width: 100%
|
|
||||||
+border-top-radius($radius)
|
|
||||||
|
|
||||||
.color-thief-output
|
|
||||||
display: none
|
|
||||||
padding: 1.5rem
|
|
||||||
background-color: white
|
|
||||||
border: 1px solid $border-color
|
|
||||||
border-top-width: 0
|
|
||||||
+border-bottom-radius($radius)
|
|
||||||
|
|
||||||
.function-title
|
|
||||||
margin-top: 0
|
|
||||||
|
|
||||||
.function
|
|
||||||
margin-bottom: 1.5rem
|
|
||||||
|
|
||||||
.swatch
|
|
||||||
display: inline-block
|
|
||||||
margin: 0
|
|
||||||
background: #dddddd
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
.swatch
|
|
||||||
margin-right: -2px
|
|
||||||
|
|
||||||
.get-color
|
|
||||||
.swatch
|
|
||||||
width: 6rem
|
|
||||||
height: 3rem
|
|
||||||
|
|
||||||
.get-palette
|
|
||||||
.swatch
|
|
||||||
width: 3rem
|
|
||||||
height: 2rem
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
.get-palette
|
|
||||||
.swatch
|
|
||||||
width: 4rem
|
|
||||||
height: 2.7rem
|
|
||||||
|
|
||||||
canvas
|
|
||||||
display: none
|
|
||||||
|
|
||||||
|
|
||||||
/* -- Credits -- */
|
|
||||||
|
|
||||||
footer
|
|
||||||
padding: 2rem 0
|
|
||||||
background-color: $header-bg-color
|
|
||||||
text-align: center
|
|
||||||
p
|
|
||||||
text-align: center
|
|
||||||
.button
|
|
||||||
margin-top: 0.5rem
|
|
||||||
|
|
||||||
/* -- Sharing -- */
|
|
||||||
|
|
||||||
.sharing-section
|
|
||||||
position: fixed
|
|
||||||
z-index: $sharing-section-z-index
|
|
||||||
top: 20px
|
|
||||||
right: 0
|
|
||||||
|
|
||||||
|
|
||||||
/* -- Drag and drop ------------------------------------------------------------------ */
|
|
||||||
|
|
||||||
.drag-drop-section
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.drop-zone
|
|
||||||
height: 25rem
|
|
||||||
margin-bottom: 4rem
|
|
||||||
background-color: $gray-dark
|
|
||||||
+border-radius($radius)
|
|
||||||
&.dragging
|
|
||||||
font-weight: 700
|
|
||||||
+box-shadow(inset 0 0 0 8px $link-color)
|
|
||||||
.drop-zone-label
|
|
||||||
color: $link-color
|
|
||||||
.default-label
|
|
||||||
display: none
|
|
||||||
.dragging-label
|
|
||||||
display: block
|
|
||||||
|
|
||||||
.drop-zone-label
|
|
||||||
position: relative
|
|
||||||
top: 11rem
|
|
||||||
color: $yellow
|
|
||||||
font-size: 1.8rem
|
|
||||||
text-align: center
|
|
||||||
pointer-events: none
|
|
||||||
text-transform: uppercase
|
|
||||||
+border-radius($radius)
|
|
||||||
|
|
||||||
@media (min-width: 40rem)
|
|
||||||
.drop-zone-label
|
|
||||||
top: 10.5rem
|
|
||||||
font-size: 2.4rem
|
|
||||||
|
|
||||||
.dragging-label
|
|
||||||
display: none
|
|
||||||
|
|
||||||
.dropped-image
|
|
||||||
.run-functions-button
|
|
||||||
display: none
|
|
||||||
.targetImage
|
|
||||||
// width: 100%
|
|
||||||
|
|
||||||
|
|
||||||
110
index.html
Executable file → Normal file
@@ -16,111 +16,49 @@
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<header>
|
|
||||||
<div class="container">
|
|
||||||
<h1 class="logo">Color Thief</h1>
|
|
||||||
<p class="lead">
|
|
||||||
Grab the color palette from an image.<br /> Uses Javascript and the canvas tag to make it happen.
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<a href="https://github.com/lokesh/color-thief/" class="button">
|
|
||||||
Download from Github</small>
|
|
||||||
</a>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</header>
|
|
||||||
|
|
||||||
<section id="examples" class="examples-section">
|
|
||||||
<div class="container">
|
|
||||||
<h2>Examples</h2>
|
|
||||||
<div id="example-images"></div>
|
<div id="example-images"></div>
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section id="drag-drop" class="drag-drop-section">
|
<script id='image-tpl' type='text/x-mustache'>
|
||||||
<div class="container">
|
{{#.}}
|
||||||
<h2>Try it yourself</h2>
|
<div class="image-section" data-image="{{.}}">
|
||||||
<div id="drop-zone" class="drop-zone">
|
<h2>{{.}}</h2>
|
||||||
<div class="drop-zone-label default-label">Drag an image here</div>
|
<img class="image" src="./examples/img/{{.}}" />
|
||||||
<div class="drop-zone-label dragging-label">Drop it!</div>
|
<div class="output"></div>
|
||||||
</div>
|
</div>
|
||||||
<div id="dragged-images" class="dragged-images"></div>
|
{{/.}}
|
||||||
</div>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<footer>
|
|
||||||
<div class="container">
|
|
||||||
<p>
|
|
||||||
Created by Lokesh Dhakar<br />
|
|
||||||
<a href="https://twitter.com/lokesh" class="button button-minor">Follow me on Twitter</a>
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
</footer>
|
|
||||||
|
|
||||||
<div id="sharing" class="sharing-section">
|
|
||||||
<a href="https://twitter.com/share" class="twitter-share-button" data-via="lokesh" data-size="large">Tweet</a>
|
|
||||||
<script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- Mustache templates -->
|
|
||||||
<script id='image-section-template' type='text/x-mustache'>
|
|
||||||
{{#images}}
|
|
||||||
<div class="image-section {{class}}">
|
|
||||||
<div class="image-wrap">
|
|
||||||
<button class="run-functions-button">
|
|
||||||
<span class="no-touch-label">Click</span>
|
|
||||||
<span class="touch-label">Tap</span>
|
|
||||||
</button>
|
|
||||||
<img class="target-image" src="{{file}}" />
|
|
||||||
</div>
|
|
||||||
<div class="color-thief-output"></div>
|
|
||||||
</div>
|
|
||||||
{{/images}}
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script id="color-thief-output-template" type="text/x-mustache">
|
<script id="color-tpl" type="text/x-mustache">
|
||||||
<div class="function get-color">
|
<div class="color">
|
||||||
<h3 class="function-title">Dominant Color</h3>
|
<h3>getColor(img)</h3>
|
||||||
<div class="swatches">
|
<div class="swatches">
|
||||||
<div class="swatch" style="background-color: rgb({{color.0}}, {{color.1}}, {{color.2}})"></div>
|
<div class="swatch" style="background-color: rgb({{color.0}}, {{color.1}}, {{color.2}})"></div>
|
||||||
</div>
|
</div>
|
||||||
<div class="function-code">
|
<code>
|
||||||
<code>colorThief.getColor(image):{{elapsedTimeForGetColor}}ms</code>
|
<div class="output-color">{{colorStr}}</div>
|
||||||
|
<div class="time">{{elapsedTime}}ms</div>
|
||||||
|
</code>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</script>
|
||||||
<div class="function get-palette">
|
|
||||||
<h3 class="function-title">Palette</h3>
|
<script id="palette-tpl" type="text/x-mustache">
|
||||||
<div class="function-output">
|
<div class="palette" data-count="{{count}}">
|
||||||
|
<h3>getPalette(img, {{count}})</h3>
|
||||||
<div class="swatches">
|
<div class="swatches">
|
||||||
{{#palette}}
|
{{#palette}}
|
||||||
<div class="swatch" style="background-color: rgb({{0}}, {{1}}, {{2}})"></div>
|
<div class="swatch" style="background-color: rgb({{0}}, {{1}}, {{2}})"></div>
|
||||||
{{/palette}}
|
{{/palette}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<code>
|
||||||
<div class="function-code">
|
<div class="output-palette">{{paletteStr}}</div>
|
||||||
<code>colorThief.getPalette(image):{{elapsedTimeForGetPalette}}ms</code>
|
<div class="time">{{elapsedTime}}ms</div>
|
||||||
</div>
|
</code>
|
||||||
</div>
|
</div>
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
||||||
<script src="src/color-thief.js"></script>
|
<script src="src/color-thief.js"></script>
|
||||||
<script src="examples/js/jquery.js"></script>
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/mustache.js/3.0.1/mustache.min.js"></script>
|
||||||
<script src="examples/js/mustache.js"></script>
|
|
||||||
<script src="examples/js/demo.js"></script>
|
<script src="examples/js/demo.js"></script>
|
||||||
|
|
||||||
<script type="text/javascript">
|
|
||||||
var _gaq = _gaq || [];
|
|
||||||
_gaq.push(['_setAccount', 'UA-2196019-1']);
|
|
||||||
_gaq.push(['_trackPageview']);
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
|
|
||||||
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
|
|
||||||
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
|
|
||||||
})();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
2549
package-lock.json
generated
Normal file
31
package.json
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "color-thief",
|
"name": "color-thief",
|
||||||
"version": "2.0.2",
|
"version": "2.0.1",
|
||||||
"author": {
|
"author": {
|
||||||
"name": "Lokesh Dhakar",
|
"name": "Lokesh Dhakar",
|
||||||
"email": "lokesh.dhakar@gmail.com",
|
"email": "lokesh.dhakar@gmail.com",
|
||||||
@@ -21,23 +21,22 @@
|
|||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/lokesh/color-thief.git"
|
"url": "https://github.com/lokesh/color-thief.git"
|
||||||
},
|
},
|
||||||
"bugs": {
|
"license": "MIT",
|
||||||
"url": "https://github.com/lokesh/color-thief/issues"
|
"scripts": {
|
||||||
|
"build": "node ./build/build.js",
|
||||||
|
"dev": "./node_modules/http-server/bin/http-server",
|
||||||
|
"test": "./node_modules/.bin/cypress open"
|
||||||
},
|
},
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "MIT",
|
|
||||||
"url": "https://raw.githubusercontent.com/lokesh/color-thief/master/LICENSE/"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"main": "dist/color-thief.min.js",
|
"main": "dist/color-thief.min.js",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"grunt": "~1.0.1",
|
"@node-minify/core": "^4.0.5",
|
||||||
"grunt-contrib-watch": "^1.0.0",
|
"@node-minify/uglify-es": "^4.0.5",
|
||||||
"grunt-contrib-connect": "^1.0.2",
|
"cypress": "^3.3.1",
|
||||||
"grunt-contrib-uglify": "~2.0.0",
|
"eslint": "^5.16.0",
|
||||||
"grunt-contrib-jshint": "~1.0.0",
|
"http-server": "^0.11.1",
|
||||||
"grunt-jscs": "^1.8.0",
|
"mustache": "^3.0.1"
|
||||||
"grunt-contrib-jshint": "^0.11.2"
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=10.15.3"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
*
|
*
|
||||||
* License
|
* License
|
||||||
* -------
|
* -------
|
||||||
* Copyright 2011, 2015 Lokesh Dhakar
|
* Copyright Lokesh Dhakar
|
||||||
* Released under the MIT license
|
* Released under the MIT license
|
||||||
* https://raw.githubusercontent.com/lokesh/color-thief/master/LICENSE
|
* https://raw.githubusercontent.com/lokesh/color-thief/master/LICENSE
|
||||||
*
|
*
|
||||||
@@ -24,26 +24,17 @@
|
|||||||
It also simplifies some of the canvas context manipulation
|
It also simplifies some of the canvas context manipulation
|
||||||
with a set of helper functions.
|
with a set of helper functions.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
var CanvasImage = function (image) {
|
var CanvasImage = function (image) {
|
||||||
this.canvas = document.createElement('canvas');
|
this.canvas = document.createElement('canvas');
|
||||||
this.context = this.canvas.getContext('2d');
|
this.context = this.canvas.getContext('2d');
|
||||||
|
|
||||||
document.body.appendChild(this.canvas);
|
|
||||||
|
|
||||||
this.width = this.canvas.width = image.width;
|
this.width = this.canvas.width = image.width;
|
||||||
this.height = this.canvas.height = image.height;
|
this.height = this.canvas.height = image.height;
|
||||||
|
|
||||||
this.context.drawImage(image, 0, 0, this.width, this.height);
|
this.context.drawImage(image, 0, 0, this.width, this.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.clear = function () {
|
|
||||||
this.context.clearRect(0, 0, this.width, this.height);
|
|
||||||
};
|
|
||||||
|
|
||||||
CanvasImage.prototype.update = function (imageData) {
|
|
||||||
this.context.putImageData(imageData, 0, 0);
|
|
||||||
};
|
|
||||||
|
|
||||||
CanvasImage.prototype.getPixelCount = function () {
|
CanvasImage.prototype.getPixelCount = function () {
|
||||||
return this.width * this.height;
|
return this.width * this.height;
|
||||||
};
|
};
|
||||||
@@ -52,11 +43,6 @@ CanvasImage.prototype.getImageData = function () {
|
|||||||
return this.context.getImageData(0, 0, this.width, this.height);
|
return this.context.getImageData(0, 0, this.width, this.height);
|
||||||
};
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.removeCanvas = function () {
|
|
||||||
this.canvas.parentNode.removeChild(this.canvas);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
var ColorThief = function () {};
|
var ColorThief = function () {};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -132,14 +118,11 @@ ColorThief.prototype.getPalette = function(sourceImage, colorCount, quality) {
|
|||||||
var cmap = MMCQ.quantize(pixelArray, colorCount);
|
var cmap = MMCQ.quantize(pixelArray, colorCount);
|
||||||
var palette = cmap? cmap.palette() : null;
|
var palette = cmap? cmap.palette() : null;
|
||||||
|
|
||||||
// Clean up
|
|
||||||
image.removeCanvas();
|
|
||||||
|
|
||||||
return palette;
|
return palette;
|
||||||
};
|
};
|
||||||
|
|
||||||
ColorThief.prototype.getColorFromUrl = function(imageUrl, callback, quality) {
|
ColorThief.prototype.getColorFromUrl = function(imageUrl, callback, quality) {
|
||||||
sourceImage = document.createElement("img");
|
let sourceImage = document.createElement("img");
|
||||||
var thief = this;
|
var thief = this;
|
||||||
sourceImage.addEventListener('load' , function(){
|
sourceImage.addEventListener('load' , function(){
|
||||||
var palette = thief.getPalette(sourceImage, 5, quality);
|
var palette = thief.getPalette(sourceImage, 5, quality);
|
||||||
@@ -151,19 +134,19 @@ ColorThief.prototype.getColorFromUrl = function(imageUrl, callback, quality) {
|
|||||||
|
|
||||||
|
|
||||||
ColorThief.prototype.getImageData = function(imageUrl, callback) {
|
ColorThief.prototype.getImageData = function(imageUrl, callback) {
|
||||||
xhr = new XMLHttpRequest();
|
let xhr = new XMLHttpRequest();
|
||||||
xhr.open('GET', imageUrl, true);
|
xhr.open('GET', imageUrl, true);
|
||||||
xhr.responseType = 'arraybuffer'
|
xhr.responseType = 'arraybuffer'
|
||||||
xhr.onload = function(e) {
|
xhr.onload = function() {
|
||||||
if (this.status == 200) {
|
if (this.status == 200) {
|
||||||
uInt8Array = new Uint8Array(this.response)
|
let uInt8Array = new Uint8Array(this.response)
|
||||||
i = uInt8Array.length
|
i = uInt8Array.length
|
||||||
binaryString = new Array(i);
|
let binaryString = new Array(i);
|
||||||
for (var i = 0; i < uInt8Array.length; i++){
|
for (var i = 0; i < uInt8Array.length; i++){
|
||||||
binaryString[i] = String.fromCharCode(uInt8Array[i])
|
binaryString[i] = String.fromCharCode(uInt8Array[i])
|
||||||
}
|
}
|
||||||
data = binaryString.join('')
|
let data = binaryString.join('')
|
||||||
base64 = window.btoa(data)
|
let base64 = window.btoa(data)
|
||||||
callback ("data:image/png;base64,"+base64)
|
callback ("data:image/png;base64,"+base64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -173,7 +156,7 @@ ColorThief.prototype.getImageData = function(imageUrl, callback) {
|
|||||||
ColorThief.prototype.getColorAsync = function(imageUrl, callback, quality) {
|
ColorThief.prototype.getColorAsync = function(imageUrl, callback, quality) {
|
||||||
var thief = this;
|
var thief = this;
|
||||||
this.getImageData(imageUrl, function(imageData){
|
this.getImageData(imageUrl, function(imageData){
|
||||||
sourceImage = document.createElement("img");
|
let sourceImage = document.createElement("img");
|
||||||
sourceImage.addEventListener('load' , function(){
|
sourceImage.addEventListener('load' , function(){
|
||||||
var palette = thief.getPalette(sourceImage, 5, quality);
|
var palette = thief.getPalette(sourceImage, 5, quality);
|
||||||
var dominantColor = palette[0];
|
var dominantColor = palette[0];
|
||||||
@@ -243,10 +226,10 @@ var newPixels = myPixels.map(function(p) {
|
|||||||
*/
|
*/
|
||||||
var MMCQ = (function() {
|
var MMCQ = (function() {
|
||||||
// private constants
|
// private constants
|
||||||
var sigbits = 5,
|
var sigbits = 5;
|
||||||
rshift = 8 - sigbits,
|
var rshift = 8 - sigbits;
|
||||||
maxIterations = 1000,
|
var maxIterations = 1000;
|
||||||
fractByPopulations = 0.75;
|
var fractByPopulations = 0.75;
|
||||||
|
|
||||||
// get reduced-space color index for a pixel
|
// get reduced-space color index for a pixel
|
||||||
function getColorIndex(r, g, b) {
|
function getColorIndex(r, g, b) {
|
||||||
@@ -255,8 +238,8 @@ var MMCQ = (function() {
|
|||||||
|
|
||||||
// Simple priority queue
|
// Simple priority queue
|
||||||
function PQueue(comparator) {
|
function PQueue(comparator) {
|
||||||
var contents = [],
|
var contents = [];
|
||||||
sorted = false;
|
var sorted = false;
|
||||||
|
|
||||||
function sort() {
|
function sort() {
|
||||||
contents.sort(comparator);
|
contents.sort(comparator);
|
||||||
@@ -310,11 +293,11 @@ var MMCQ = (function() {
|
|||||||
return vbox._volume;
|
return vbox._volume;
|
||||||
},
|
},
|
||||||
count: function(force) {
|
count: function(force) {
|
||||||
var vbox = this,
|
var vbox = this;
|
||||||
histo = vbox.histo;
|
var histo = vbox.histo;
|
||||||
if (!vbox._count_set || force) {
|
if (!vbox._count_set || force) {
|
||||||
var npix = 0,
|
var npix = 0;
|
||||||
index, i, j, k;
|
var index; var i; var j; var k;
|
||||||
for (i = vbox.r1; i <= vbox.r2; i++) {
|
for (i = vbox.r1; i <= vbox.r2; i++) {
|
||||||
for (j = vbox.g1; j <= vbox.g2; j++) {
|
for (j = vbox.g1; j <= vbox.g2; j++) {
|
||||||
for (k = vbox.b1; k <= vbox.b2; k++) {
|
for (k = vbox.b1; k <= vbox.b2; k++) {
|
||||||
@@ -333,16 +316,17 @@ var MMCQ = (function() {
|
|||||||
return new VBox(vbox.r1, vbox.r2, vbox.g1, vbox.g2, vbox.b1, vbox.b2, vbox.histo);
|
return new VBox(vbox.r1, vbox.r2, vbox.g1, vbox.g2, vbox.b1, vbox.b2, vbox.histo);
|
||||||
},
|
},
|
||||||
avg: function(force) {
|
avg: function(force) {
|
||||||
var vbox = this,
|
var vbox = this;
|
||||||
histo = vbox.histo;
|
var histo = vbox.histo;
|
||||||
if (!vbox._avg || force) {
|
if (!vbox._avg || force) {
|
||||||
var ntot = 0,
|
var ntot = 0;
|
||||||
mult = 1 << (8 - sigbits),
|
var mult = 1 << (8 - sigbits);
|
||||||
rsum = 0,
|
var rsum = 0;
|
||||||
gsum = 0,
|
var gsum = 0;
|
||||||
bsum = 0,
|
var bsum = 0;
|
||||||
hval,
|
var hval;
|
||||||
i, j, k, histoindex;
|
var i, j, k;
|
||||||
|
var histoindex;
|
||||||
for (i = vbox.r1; i <= vbox.r2; i++) {
|
for (i = vbox.r1; i <= vbox.r2; i++) {
|
||||||
for (j = vbox.g1; j <= vbox.g2; j++) {
|
for (j = vbox.g1; j <= vbox.g2; j++) {
|
||||||
for (k = vbox.b1; k <= vbox.b2; k++) {
|
for (k = vbox.b1; k <= vbox.b2; k++) {
|
||||||
@@ -369,10 +353,10 @@ var MMCQ = (function() {
|
|||||||
return vbox._avg;
|
return vbox._avg;
|
||||||
},
|
},
|
||||||
contains: function(pixel) {
|
contains: function(pixel) {
|
||||||
var vbox = this,
|
var vbox = this;
|
||||||
rval = pixel[0] >> rshift,
|
var rval = pixel[0] >> rshift;
|
||||||
gval = pixel[1] >> rshift,
|
var gval = pixel[1] >> rshift;
|
||||||
bval = pixel[2] >> rshift;
|
var bval = pixel[2] >> rshift;
|
||||||
return (rval >= vbox.r1 && rval <= vbox.r2 &&
|
return (rval >= vbox.r1 && rval <= vbox.r2 &&
|
||||||
gval >= vbox.g1 && gval <= vbox.g2 &&
|
gval >= vbox.g1 && gval <= vbox.g2 &&
|
||||||
bval >= vbox.b1 && bval <= vbox.b2);
|
bval >= vbox.b1 && bval <= vbox.b2);
|
||||||
@@ -411,8 +395,10 @@ var MMCQ = (function() {
|
|||||||
return this.nearest(color);
|
return this.nearest(color);
|
||||||
},
|
},
|
||||||
nearest: function(color) {
|
nearest: function(color) {
|
||||||
var vboxes = this.vboxes,
|
var vboxes = this.vboxes;
|
||||||
d1, d2, pColor;
|
var d1;
|
||||||
|
var d2;
|
||||||
|
var pColor;
|
||||||
for (var i=0; i<vboxes.size(); i++) {
|
for (var i=0; i<vboxes.size(); i++) {
|
||||||
d2 = Math.sqrt(
|
d2 = Math.sqrt(
|
||||||
Math.pow(color[0] - vboxes.peek(i).color[0], 2) +
|
Math.pow(color[0] - vboxes.peek(i).color[0], 2) +
|
||||||
@@ -437,8 +423,8 @@ var MMCQ = (function() {
|
|||||||
vboxes[0].color = [0,0,0];
|
vboxes[0].color = [0,0,0];
|
||||||
|
|
||||||
// force lightest color to white if everything > 251
|
// force lightest color to white if everything > 251
|
||||||
var idx = vboxes.length-1,
|
var idx = vboxes.length-1;
|
||||||
highest = vboxes[idx].color;
|
var highest = vboxes[idx].color;
|
||||||
if (highest[0] > 251 && highest[1] > 251 && highest[2] > 251)
|
if (highest[0] > 251 && highest[1] > 251 && highest[2] > 251)
|
||||||
vboxes[idx].color = [255,255,255];
|
vboxes[idx].color = [255,255,255];
|
||||||
}
|
}
|
||||||
@@ -447,9 +433,9 @@ var MMCQ = (function() {
|
|||||||
// histo (1-d array, giving the number of pixels in
|
// histo (1-d array, giving the number of pixels in
|
||||||
// each quantized region of color space), or null on error
|
// each quantized region of color space), or null on error
|
||||||
function getHisto(pixels) {
|
function getHisto(pixels) {
|
||||||
var histosize = 1 << (3 * sigbits),
|
var histosize = 1 << (3 * sigbits);
|
||||||
histo = new Array(histosize),
|
var histo = new Array(histosize);
|
||||||
index, rval, gval, bval;
|
var index; var rval; var gval; var bval;
|
||||||
pixels.forEach(function(pixel) {
|
pixels.forEach(function(pixel) {
|
||||||
rval = pixel[0] >> rshift;
|
rval = pixel[0] >> rshift;
|
||||||
gval = pixel[1] >> rshift;
|
gval = pixel[1] >> rshift;
|
||||||
@@ -461,10 +447,10 @@ var MMCQ = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function vboxFromPixels(pixels, histo) {
|
function vboxFromPixels(pixels, histo) {
|
||||||
var rmin=1000000, rmax=0,
|
var rmin=1000000; var rmax=0;
|
||||||
gmin=1000000, gmax=0,
|
var gmin=1000000; var gmax=0;
|
||||||
bmin=1000000, bmax=0,
|
var bmin=1000000; var bmax=0;
|
||||||
rval, gval, bval;
|
var rval; var gval; var bval;
|
||||||
// find min/max
|
// find min/max
|
||||||
pixels.forEach(function(pixel) {
|
pixels.forEach(function(pixel) {
|
||||||
rval = pixel[0] >> rshift;
|
rval = pixel[0] >> rshift;
|
||||||
@@ -483,19 +469,19 @@ var MMCQ = (function() {
|
|||||||
function medianCutApply(histo, vbox) {
|
function medianCutApply(histo, vbox) {
|
||||||
if (!vbox.count()) return;
|
if (!vbox.count()) return;
|
||||||
|
|
||||||
var rw = vbox.r2 - vbox.r1 + 1,
|
var rw = vbox.r2 - vbox.r1 + 1;
|
||||||
gw = vbox.g2 - vbox.g1 + 1,
|
var gw = vbox.g2 - vbox.g1 + 1;
|
||||||
bw = vbox.b2 - vbox.b1 + 1,
|
var bw = vbox.b2 - vbox.b1 + 1;
|
||||||
maxw = pv.max([rw, gw, bw]);
|
var maxw = pv.max([rw, gw, bw]);
|
||||||
// only one pixel, no split
|
// only one pixel, no split
|
||||||
if (vbox.count() == 1) {
|
if (vbox.count() == 1) {
|
||||||
return [vbox.copy()];
|
return [vbox.copy()];
|
||||||
}
|
}
|
||||||
/* Find the partial sum arrays along the selected axis. */
|
/* Find the partial sum arrays along the selected axis. */
|
||||||
var total = 0,
|
var total = 0;
|
||||||
partialsum = [],
|
var partialsum = [];
|
||||||
lookaheadsum = [],
|
var lookaheadsum = [];
|
||||||
i, j, k, sum, index;
|
var i; var j; var k; var sum; var index;
|
||||||
if (maxw == rw) {
|
if (maxw == rw) {
|
||||||
for (i = vbox.r1; i <= vbox.r2; i++) {
|
for (i = vbox.r1; i <= vbox.r2; i++) {
|
||||||
sum = 0;
|
sum = 0;
|
||||||
@@ -539,9 +525,9 @@ var MMCQ = (function() {
|
|||||||
lookaheadsum[i] = total-d;
|
lookaheadsum[i] = total-d;
|
||||||
});
|
});
|
||||||
function doCut(color) {
|
function doCut(color) {
|
||||||
var dim1 = color + '1',
|
var dim1 = color + '1';
|
||||||
dim2 = color + '2',
|
var dim2 = color + '2';
|
||||||
left, right, vbox1, vbox2, d2, count2=0;
|
var left; var right; var vbox1; var vbox2; var d2; var count2=0;
|
||||||
for (i = vbox[dim1]; i <= vbox[dim2]; i++) {
|
for (i = vbox[dim1]; i <= vbox[dim2]; i++) {
|
||||||
if (partialsum[i] > total / 2) {
|
if (partialsum[i] > total / 2) {
|
||||||
vbox1 = vbox.copy();
|
vbox1 = vbox.copy();
|
||||||
@@ -579,8 +565,8 @@ var MMCQ = (function() {
|
|||||||
|
|
||||||
// XXX: check color content and convert to grayscale if insufficient
|
// XXX: check color content and convert to grayscale if insufficient
|
||||||
|
|
||||||
var histo = getHisto(pixels),
|
var histo = getHisto(pixels);
|
||||||
histosize = 1 << (3 * sigbits);
|
// histosize = 1 << (3 * sigbits);
|
||||||
|
|
||||||
// check that we aren't below maxcolors already
|
// check that we aren't below maxcolors already
|
||||||
var nColors = 0;
|
var nColors = 0;
|
||||||
@@ -590,15 +576,15 @@ var MMCQ = (function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get the beginning vbox from the colors
|
// get the beginning vbox from the colors
|
||||||
var vbox = vboxFromPixels(pixels, histo),
|
var vbox = vboxFromPixels(pixels, histo);
|
||||||
pq = new PQueue(function(a,b) { return pv.naturalOrder(a.count(), b.count()); });
|
var pq = new PQueue(function(a,b) { return pv.naturalOrder(a.count(), b.count()); });
|
||||||
pq.push(vbox);
|
pq.push(vbox);
|
||||||
|
|
||||||
// inner function to do the iteration
|
// inner function to do the iteration
|
||||||
function iter(lh, target) {
|
function iter(lh, target) {
|
||||||
var ncolors = 1,
|
var ncolors = 1;
|
||||||
niters = 0,
|
var niters = 0;
|
||||||
vbox;
|
var vbox;
|
||||||
while (niters < maxIterations) {
|
while (niters < maxIterations) {
|
||||||
vbox = lh.pop();
|
vbox = lh.pop();
|
||||||
if (!vbox.count()) { /* just put it back */
|
if (!vbox.count()) { /* just put it back */
|
||||||
@@ -607,9 +593,9 @@ var MMCQ = (function() {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// do the cut
|
// do the cut
|
||||||
var vboxes = medianCutApply(histo, vbox),
|
var vboxes = medianCutApply(histo, vbox);
|
||||||
vbox1 = vboxes[0],
|
var vbox1 = vboxes[0];
|
||||||
vbox2 = vboxes[1];
|
var vbox2 = vboxes[1];
|
||||||
|
|
||||||
if (!vbox1) {
|
if (!vbox1) {
|
||||||
// console.log("vbox1 not defined; shouldn't happen!");
|
// console.log("vbox1 not defined; shouldn't happen!");
|
||||||
|
|||||||