├── .gitignore ├── media └── imgcolr.swf ├── test ├── images │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ └── 6.jpg ├── test.vhtml5.js ├── test.js ├── qunit │ ├── index.html │ └── tests.js ├── test.html └── test.vhtml5.html ├── src ├── shortcut.js ├── outer.js ├── amd-support.js ├── plugin.js ├── color.js └── appendFlash.js ├── .jshintrc ├── package.json ├── as_src ├── ImageLoader.as └── Imgcolr.as ├── imgcolr.jquery.json ├── imgcolr.html5.min.js ├── imgcolr.min.js ├── Gruntfile.js ├── README.md ├── imgcolr.html5.js └── imgcolr.js /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | .idea 4 | .DS_Store -------------------------------------------------------------------------------- /media/imgcolr.swf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/media/imgcolr.swf -------------------------------------------------------------------------------- /test/images/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/test/images/1.jpg -------------------------------------------------------------------------------- /test/images/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/test/images/2.jpg -------------------------------------------------------------------------------- /test/images/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/test/images/3.jpg -------------------------------------------------------------------------------- /test/images/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/test/images/4.jpg -------------------------------------------------------------------------------- /test/images/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/test/images/5.jpg -------------------------------------------------------------------------------- /test/images/6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/swaydeng/imgcolr/HEAD/test/images/6.jpg -------------------------------------------------------------------------------- /src/shortcut.js: -------------------------------------------------------------------------------- 1 | define(function () { 2 | // shortcut for Imgcolr 3 | var Imgcolr = {}; 4 | }); -------------------------------------------------------------------------------- /src/outer.js: -------------------------------------------------------------------------------- 1 | define(['Imgcolr'], function (Imgcolr) { 2 | 3 | // The top-level namespace, so that so that the method Imgcolr.color can be invoked from swf 4 | window.Imgcolr = Imgcolr; 5 | 6 | }); -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "curly": true, 3 | "eqeqeq": true, 4 | "eqnull": true, 5 | "browser": true, 6 | "indent": 2, 7 | "undef": true, 8 | "unused": true, 9 | // "devel": false, 10 | "globals": { 11 | "jQuery": true, 12 | "define": true 13 | } 14 | } -------------------------------------------------------------------------------- /src/amd-support.js: -------------------------------------------------------------------------------- 1 | define(['jQuery', 'Imgcolr'], function ($, Imgcolr) { 2 | 3 | // AMD module support 4 | Imgcolr.imgcolr = function (elem, selector, options) { 5 | $(elem).imgcolr(selector, options); 6 | }; 7 | 8 | if (typeof define === 'function' && define.amd) { 9 | define('imgcolr', [], function () { return Imgcolr; }); 10 | } 11 | 12 | }); -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "imgcolr", 3 | "version": "1.0.1", 4 | "author": "Sway Deng", 5 | "devDependencies": { 6 | "grunt": "~0.4.1", 7 | "grunt-contrib-uglify": "~0.2.4", 8 | "grunt-contrib-concat": "~0.3.0", 9 | "grunt-contrib-clean": "~0.5.0", 10 | "grunt-contrib-jshint": "~0.6.4", 11 | "grunt-contrib-qunit": "~0.2.2" 12 | }, 13 | "license": "MIT" 14 | } 15 | -------------------------------------------------------------------------------- /as_src/ImageLoader.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | import flash.display.Loader; 4 | 5 | /** 6 | * ... 7 | * @author Sway Deng 8 | */ 9 | public class ImageLoader extends Loader { 10 | 11 | public var ignore:String; 12 | 13 | public function ImageLoader (ignore:String='') { 14 | super(); 15 | 16 | this.ignore = ignore; 17 | } 18 | 19 | } 20 | 21 | } -------------------------------------------------------------------------------- /test/test.vhtml5.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | 3 | $(function () { 4 | $('#btn').click(function () { 5 | 6 | $('div.normal img').imgcolr(); 7 | 8 | $('div.multiple img').imgcolr('.inner-box'); 9 | 10 | $('div.isolate img').imgcolr(function (elem, color) { 11 | console.log(this, elem, color); 12 | console.log(this === elem); 13 | }).imgcolr(function () { 14 | return $(this).prev('.text'); 15 | }); 16 | 17 | $('div.ignore img').imgcolr({ ignore: 'lrb' }); 18 | 19 | }); 20 | }); 21 | 22 | })(jQuery); -------------------------------------------------------------------------------- /test/test.js: -------------------------------------------------------------------------------- 1 | (function ($) { 2 | Imgcolr.setSwf('http://view.1688.com/book/swfapp/imgcolr/imgcolr.swf'); 3 | $(function () { 4 | $('#btn').click(function () { 5 | 6 | $('div.normal img').imgcolr(); 7 | 8 | $('div.multiple img').imgcolr('.inner-box'); 9 | 10 | $('div.isolate img').imgcolr(function (elem, color) { 11 | console.log(this, elem, color); 12 | console.log(this === elem); 13 | }).imgcolr(function () { 14 | return $(this).prev('.text'); 15 | }); 16 | 17 | $('div.ignore img').imgcolr({ ignore: 'lrb' }); 18 | 19 | // data-imgcolr-ignore 20 | 21 | }); 22 | }); 23 | 24 | })(jQuery); -------------------------------------------------------------------------------- /test/qunit/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | QUnit Tests 6 | 7 | 8 | 9 |
10 |
11 | 12 |
13 |
14 | 15 |
16 |
17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /test/qunit/tests.js: -------------------------------------------------------------------------------- 1 | /* 2 | module('default group', { 3 | setup:function () {}, 4 | teardown:function () {} 5 | }); 6 | */ 7 | 8 | var $ = jQuery; 9 | var root = $('#imgset-test'); 10 | 11 | Imgcolr.setSwf('http://view.1688.com/book/swfapp/imgcolr/imgcolr.swf'); 12 | 13 | test('globals set up', function() { 14 | ok(window.Imgcolr, 'global object Imgcolr is created'); 15 | }); 16 | 17 | test('jQuery plugin method set up', function() { 18 | ok(jQuery.fn.imgcolr, '$.fn.imgcolr is created'); 19 | }); 20 | 21 | // the img site does not allow to access 22 | 23 | // retrived right color 24 | asyncTest('retrive color', 1, function () { 25 | 26 | $('div.normal img', root).imgcolr().imgcolr(function () { 27 | var bgColor = this.parentNode.style.backgroundColor; 28 | strictEqual(bgColor, 'rgb(191, 191, 191)', 'parentNode\'s backgroundColor and img border color are the same'); 29 | start(); 30 | }); 31 | 32 | }); -------------------------------------------------------------------------------- /imgcolr.jquery.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "imgcolr", 3 | "title": "imgcolr grabs image color", 4 | "description": "imgcolr is a plugin for grabbing the dominant color of a given image's borders. By using it, you can make the web more interesting, for example, create a slider that the page's background color is dynamicly adapted for the current image, with a few lines of code.", 5 | "keywords": [ 6 | "color", 7 | "image", 8 | "imagecolor", 9 | "palette" 10 | ], 11 | "demo": "http://swaydeng.github.io/imgcolr", 12 | "version": "1.0.1", 13 | "author": { 14 | "name": "Sway Deng", 15 | "url": "https://github.com/swaydeng" 16 | }, 17 | "licenses": [ 18 | { 19 | "type": "MIT", 20 | "url": "http://opensource.org/licenses/MIT" 21 | } 22 | ], 23 | "bugs": "https://github.com/swaydeng/imgcolr/issues", 24 | "homepage": "https://github.com/swaydeng/imgcolr", 25 | "docs": "https://github.com/swaydeng/imgcolr#imgcolr", 26 | "download": "https://github.com/swaydeng/imgcolr/archive/master.zip", 27 | "dependencies": { 28 | "jquery": ">=1.7.2" 29 | } 30 | } -------------------------------------------------------------------------------- /src/plugin.js: -------------------------------------------------------------------------------- 1 | define(['jQuery', 'Imgcolr'], function ($, Imgcolr) { 2 | 3 | // jQuery Plugin - for example: $(elem).imgcolr() 4 | var pluginName = 'imgcolr'; 5 | 6 | function Plugin (element, selector, options) { 7 | var elem = $(element); 8 | var ignore = elem.data('imgcolrIgnore'); 9 | var defOpt = { 10 | url: element.src 11 | }; 12 | 13 | if (typeof selector === 'object') { 14 | options = selector; 15 | selector = undefined; 16 | } 17 | 18 | options = $.extend(defOpt, options); 19 | // if data-imgcolr-ignore is specified on the img node, then rewrite the options 20 | if (typeof ignore === 'string') { 21 | options.ignore = ignore; 22 | } 23 | 24 | options.success = function (data) { 25 | var matches = typeof selector === 'function' ? selector.call(element, element, data.color) : 26 | typeof selector === 'string' ? elem.parents(selector) : elem.parent(); 27 | // for `selector.call(element, element, data.color)` may not return a jQuery object 28 | if (matches && matches.jquery) { 29 | matches.css('backgroundColor', data.color); 30 | } 31 | }; 32 | 33 | Imgcolr.color(options); 34 | } 35 | 36 | // @param selector {Selector | Function}[optional] 37 | // @param {string} options.ignore - Which border should be ignored, 38 | // there are 4 kinds of values: 't', 'r', 'b', 'l', you can ignore multiple borders like this: 'tb', it's optional 39 | $.fn[pluginName] = function (selector, options) { 40 | return this.each(function () { 41 | new Plugin(this, selector, options); 42 | }); 43 | }; 44 | 45 | }); -------------------------------------------------------------------------------- /imgcolr.html5.min.js: -------------------------------------------------------------------------------- 1 | /*! imgcolr v1.0.1 | Sway Deng | MIT */ 2 | !function(a,b){function c(a,c,d){var f=b(a),g=f.data("imgcolrIgnore"),h={url:a.src};"object"==typeof c&&(d=c,c=void 0),d=b.extend(h,d),"string"==typeof g&&(d.ignore=g),d.success=function(b){var d="function"==typeof c?c.call(a,a,b.color):"string"==typeof c?f.parents(c):f.parent();d&&d.jquery&&d.css("backgroundColor",b.color)},e.color(d)}var d=a.Imgcolr,e={},f={},g=document.createElement("canvas"),h="t",i="r",j="b",k="l",l=function(a){var c=f[a];return c||(c=b.Deferred(),f[a]=c),c},m=function(a){var b=a.toString(16);return 1===b.length?"0"+b:b},n=function(a,b,c){return["#",m(a),m(b),m(c)].join("")},o=function(a,b,c){var d,e=b[a+3];127>e||(d=n(b[a],b[a+1],b[a+2]),c[d]?c[d]++:c[d]=1)},p=function(a,b,c,d,e){var f,g;if(a===h||a===j)for(g=a===h?0:d-1,f=0;c>f;f++)o(4*(g*c+f),e,b);else for(d-=1,f=a===i?c-1:0,g=1;d>g;g++)o(4*(g*c+f),e,b)},q=function(a,b){var c,d,e,f="#ffffff",l=0,m={},n=a.width,o=a.height,q=g.getContext("2d");g.width=n,g.height=o,q.drawImage(a,0,0),c=q.getImageData(0,0,n,o).data,b.indexOf(h)<0&&p(h,m,n,o,c),b.indexOf(i)<0&&p(i,m,n,o,c),b.indexOf(j)<0&&p(j,m,n,o,c),b.indexOf(k)<0&&p(k,m,n,o,c);for(d in m)e=m[d],e>l&&(f=d,l=e);return f},r=function(a,b){var c=new Image,d={url:a,ignore:b};c.onload=function(){try{d.color=q(this,b),l(a).resolve(d)}catch(e){l(a).reject(d)}c=null},c.onerror=function(){c.onerror=null,c=null,l(a).reject(d)},c.crossOrigin="",c.src=a};e.color=function(a){var b=l(a.url);"function"==typeof a.success&&b.done(a.success),"function"==typeof a.error&&b.fail(a.error),"pending"===b.state()&&r(a.url,"string"==typeof a.ignore?a.ignore:"")},e.noConflict=function(){return a.Imgcolr=d,e},a.Imgcolr=e;var s="imgcolr";b.fn[s]=function(a,b){return this.each(function(){new c(this,a,b)})}}(this,jQuery); -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 27 |

28 | 29 |

30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 |
44 |
45 | 46 |
47 |
48 |
49 |
50 |
hello world
51 | 52 |
53 |
54 | 55 |
56 | 57 | -------------------------------------------------------------------------------- /imgcolr.min.js: -------------------------------------------------------------------------------- 1 | /*! imgcolr v1.0.1 | Sway Deng | MIT */ 2 | !function(a,b,c){function d(a,d,e){var f=b(a),h=f.data("imgcolrIgnore"),i={url:a.src};"object"==typeof d&&(e=d,d=c),e=b.extend(i,e),"string"==typeof h&&(e.ignore=h),e.success=function(b){var c="function"==typeof d?d.call(a,a,b.color):"string"==typeof d?f.parents(d):f.parent();c&&c.jquery&&c.css("backgroundColor",b.color)},g.color(e)}var e,f,g={},h="swfReady",i="success",j="error",k="dfd-swf",l={},m=function(a){var c=l[a];return c||(c=b.Deferred(),l[a]=c),c},n=function(c,d){var g="position:absolute; left:0; top:0; width:1px; height:1px;",h=b('
').appendTo("body");f=o(h,{width:1,height:1,wmode:"transparent",swf:e,allowScriptAccess:"always",flashvars:{allowedDomain:a.location.hostname}}),n=function(a,b){m(k).done(function(c){c.getColor(a,b)})},n(c,d)};g.setSwf=function(a){e=a},g.getSwf=function(){return e},g.trigger=function(a){switch(a.type){case h:m(k).resolve(f);break;case i:m(a.data.url).resolve(a.data);break;case j:m(a.data.url).reject(a.data)}},g.color=function(a){var b=m(a.url);"function"==typeof a.success&&b.done(a.success),"function"==typeof a.error&&b.fail(a.error),"pending"===b.state()&&n(a.url,"string"==typeof a.ignore?a.ignore:"")};var o=function(){function c(a){if(!b.isPlainObject(a))return a;var d,e,f=[],g="";for(d in a)e=a[d],g=b.isPlainObject(e)?c(e):[d,encodeURI(e)].join("="),f.push(g);return f.join("&")}function d(a){var b,c,d=[];for(b in a)c=a[b],c&&d.push([b,'="',c,'"'].join(""));return d.join(" ")}function e(a){var b=[];for(var d in a)b.push([''].join(""));return b.join("")}var f,g,h,i=!!a.attachEvent&&"[object Opera]"!==Object.prototype.toString.call(a.opera),j=navigator.plugins["Shockwave Flash"]||a.ActiveXObject;try{f=j.description?j.description:new j("ShockwaveFlash.ShockwaveFlash").GetVariable("$version")}catch(k){f="Unavailable"}return g=f.match(/\d+/g),h=!!g&&g[0]>0,function(a,c){var f;if(!c.swf||!h)return!1;f={id:"swf-"+b.guid++,width:c.width||1,height:c.height||1,style:c.style||""},i?(f.classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000",c.movie=c.swf):(f.data=c.swf,f.type="application/x-shockwave-flash"),c.wmode=c.wmode||"opaque";var g=["",e(c),""].join("");if(i){var j=document.createElement("div");a.html(j),j.outerHTML=g}else a.html(g);return a.children().get(0)}}();a.Imgcolr=g;var p="imgcolr";b.fn[p]=function(a,b){return this.each(function(){new d(this,a,b)})},g.imgcolr=function(a,c,d){b(a).imgcolr(c,d)},"function"==typeof define&&define.amd&&define("imgcolr",[],function(){return g})}(window,jQuery); -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function (grunt) { 2 | 3 | //Project config 4 | grunt.initConfig({ 5 | pkg: grunt.file.readJSON('package.json'), 6 | banner: { 7 | compact: '/*! <%= pkg.name %> v<%= pkg.version %> | <%= pkg.author %> | <%= pkg.license %> */\n', 8 | full: '/*!\n' + 9 | ' * <%= pkg.name %> v<%= pkg.version %>\n' + 10 | ' * Author: <%= pkg.author %>\n' + 11 | ' * Released under the <%= pkg.license %> license\n' + 12 | ' */' 13 | }, 14 | clean: { 15 | build: [ 16 | 'dist', 17 | '<%= pkg.name %>.html5.min.js' 18 | ] 19 | }, 20 | concat: { 21 | dist: { 22 | options: { 23 | banner: '<%= banner.full %>\n(function (window, $, undefined) {', 24 | footer: '})(window, jQuery);', 25 | process: function (src, filepath) { 26 | if ((/define\(.*?\{/).test(src)) { 27 | src = src.replace(/define\(.*?\{/, ''); 28 | src = src.replace(/\}\);\s*?$/,''); 29 | } 30 | return src; 31 | } 32 | }, 33 | src: [ 34 | 'src/shortcut.js', 35 | 'src/color.js', 36 | 'src/appendFlash.js', 37 | 'src/outer.js', 38 | 'src/plugin.js', 39 | 'src/amd-support.js' 40 | ], 41 | dest: 'dist/<%= pkg.name %>.js', 42 | nonull: true 43 | } 44 | }, 45 | jshint: { 46 | options: { 47 | jshintrc: '.jshintrc' 48 | }, 49 | files: [ 50 | 'dist/<%= pkg.name %>.js', 51 | '<%= pkg.name %>.html5.js' 52 | ] 53 | }, 54 | uglify: { 55 | options: { 56 | banner: '<%= banner.compact %>' 57 | }, 58 | build: { 59 | files: { 60 | 'dist/<%= pkg.name %>.min.js': 'dist/<%= pkg.name %>.js', 61 | '<%= pkg.name %>.html5.min.js': '<%= pkg.name %>.html5.js' 62 | } 63 | } 64 | }, 65 | qunit: { 66 | options: { 67 | urls: ['./test/qunit/index.html'] 68 | } 69 | } 70 | }); 71 | 72 | grunt.loadNpmTasks('grunt-contrib-clean'); 73 | grunt.loadNpmTasks('grunt-contrib-concat'); 74 | grunt.loadNpmTasks('grunt-contrib-jshint'); 75 | grunt.loadNpmTasks('grunt-contrib-uglify'); 76 | grunt.loadNpmTasks('grunt-contrib-qunit'); 77 | 78 | // Default task(s). 79 | grunt.registerTask('build', ['clean', 'concat', 'jshint', 'uglify']); 80 | grunt.registerTask('test', ['build', 'qunit']); 81 | grunt.registerTask('default', ['build']); 82 | 83 | }; -------------------------------------------------------------------------------- /test/test.vhtml5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 27 |

28 | 29 |

30 |
31 | 32 |
33 |
34 | 35 |
36 |
37 | 38 |
39 |
40 | 41 |
42 |
43 | 44 |
45 |
46 |
47 |
48 | 49 |
50 |
51 |
52 |
53 |
hello world
54 | 55 |
56 |
57 | 58 |
59 | 87 | 88 | -------------------------------------------------------------------------------- /src/color.js: -------------------------------------------------------------------------------- 1 | define(['jQuery', 'appendFlash', 'Imgcolr'], function ($, appendFlash, Imgcolr) { 2 | 3 | /****** some constants ******/ 4 | // event name 5 | var EVT_SWFREADY = 'swfReady'; 6 | var EVT_SUCCESS = 'success'; 7 | var EVT_ERROR = 'error'; 8 | // swf dfd keyname 9 | var DFD_SWF = 'dfd-swf'; 10 | 11 | // swf file url, swf object 12 | var swfUrl, swfObj; 13 | // all deferred objects cache 14 | var dfdCache = {}; 15 | // get or cache Deferred objects 16 | var getDfd = function (key) { 17 | var dfd = dfdCache[key]; 18 | if (!dfd) { 19 | dfd = $.Deferred(); 20 | dfdCache[key] = dfd; 21 | } 22 | return dfd; 23 | }; 24 | 25 | // swf method 26 | var compute = function (url, ignore) { 27 | var style = 'position:absolute; left:0; top:0; width:1px; height:1px;'; 28 | var swfNode = $('
').appendTo('body'); 29 | 30 | swfObj = appendFlash(swfNode, { 31 | width: 1, 32 | height: 1, 33 | wmode: 'transparent', 34 | swf: swfUrl, 35 | allowScriptAccess: 'always', 36 | flashvars: { 37 | allowedDomain: window.location.hostname 38 | } 39 | }); 40 | 41 | compute = function (url, ignore) { 42 | getDfd(DFD_SWF).done(function (obj) { 43 | obj.getColor(url, ignore); 44 | }); 45 | }; 46 | 47 | compute(url, ignore); 48 | }; 49 | // You must specify the swf url according to your scenario before using this. 50 | Imgcolr.setSwf = function (url) { 51 | swfUrl = url; 52 | }; 53 | 54 | Imgcolr.getSwf = function () { 55 | return swfUrl; 56 | }; 57 | 58 | // @private - very important, this method is called from swf internally 59 | Imgcolr.trigger = function (evtObj) { 60 | switch (evtObj.type) { 61 | case EVT_SWFREADY: 62 | getDfd(DFD_SWF).resolve(swfObj); 63 | break; 64 | case EVT_SUCCESS: 65 | getDfd(evtObj.data.url).resolve(evtObj.data); 66 | break; 67 | case EVT_ERROR: 68 | getDfd(evtObj.data.url).reject(evtObj.data); 69 | break; 70 | } 71 | }; 72 | // Imgcolr.color 73 | // ---------------- core method --------------- 74 | // @param {string} options.url - The url of the image 75 | // @param {string} options.ignore - Which border should be ignored, 76 | // there are 4 kinds of values: 't', 'r', 'b', 'l', you can ignore multiple borders like this: 'tb', it's optional 77 | // @param {function} options.success - The callback for success 78 | // @param {function} options.error - The callback for error, it's optional 79 | Imgcolr.color = function (options) { 80 | var dfd = getDfd(options.url); 81 | 82 | if (typeof options.success === 'function') { 83 | dfd.done(options.success); 84 | } 85 | 86 | if (typeof options.error === 'function') { 87 | dfd.fail(options.error); 88 | } 89 | 90 | if ('pending' === dfd.state()) { 91 | compute(options.url, typeof options.ignore === 'string' ? options.ignore : ''); 92 | } 93 | }; 94 | 95 | }); -------------------------------------------------------------------------------- /src/appendFlash.js: -------------------------------------------------------------------------------- 1 | define(['jQuery'], function ($) { 2 | 3 | var appendFlash = (function () { 4 | var version, versionNumbers, flashAvailable; 5 | // Prototype style 6 | // https://github.com/sstephenson/prototype/blob/1fb9728/src/prototype.js#L81 7 | var isIE = !!window.attachEvent && Object.prototype.toString.call(window.opera) !== '[object Opera]'; 8 | 9 | var Plugin = navigator.plugins['Shockwave Flash'] || window.ActiveXObject; 10 | 11 | try { 12 | if (Plugin.description) { 13 | version = Plugin.description; 14 | } else { 15 | version = (new Plugin('ShockwaveFlash.ShockwaveFlash')).GetVariable('$version'); 16 | } 17 | } catch (e) { 18 | version = 'Unavailable'; 19 | } 20 | versionNumbers = version.match(/\d+/g); 21 | flashAvailable = !!versionNumbers && versionNumbers[0] > 0; 22 | 23 | function buildQueryString (obj) { 24 | if (!$.isPlainObject(obj)) { 25 | return obj; 26 | } 27 | 28 | var k, v; 29 | var arr = []; 30 | var str = ''; 31 | 32 | for (k in obj) { 33 | v = obj[k]; 34 | if ($.isPlainObject(v)) { 35 | str = buildQueryString(v); 36 | } else { 37 | str = [k, encodeURI(v)].join('='); 38 | } 39 | arr.push(str); 40 | } 41 | 42 | return arr.join('&'); 43 | } 44 | 45 | // build attributes based on an object 46 | function buildAttr (obj) { 47 | var k, v; 48 | var arr = []; 49 | 50 | for (k in obj) { 51 | v = obj[k]; 52 | if (v) { 53 | arr.push([k, '="', v, '"'].join('')); 54 | } 55 | } 56 | 57 | return arr.join(' '); 58 | } 59 | 60 | function buildParamTag (obj) { 61 | var arr = []; 62 | 63 | for (var k in obj) { 64 | arr.push([''].join('')); 65 | } 66 | 67 | return arr.join(''); 68 | } 69 | 70 | // return the real method to append a flash object 71 | return function (elem, options) { 72 | var attrs; 73 | 74 | if (!options.swf || !flashAvailable) { 75 | return false; 76 | } 77 | 78 | attrs = { 79 | id: 'swf-' + ($.guid++), 80 | width: options.width || 1, 81 | height: options.height || 1, 82 | style: options.style || '' 83 | }; 84 | 85 | if (isIE) { 86 | attrs.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; 87 | options.movie = options.swf; 88 | } else { 89 | attrs.data = options.swf; 90 | attrs.type = 'application/x-shockwave-flash'; 91 | } 92 | 93 | options.wmode = options.wmode || 'opaque'; 94 | 95 | var html = ['', buildParamTag(options), ''].join(''); 96 | if (isIE) { 97 | var flashContainer = document.createElement('div'); 98 | elem.html(flashContainer); 99 | flashContainer.outerHTML = html; 100 | } else { 101 | elem.html(html); 102 | } 103 | 104 | return elem.children().get(0); 105 | }; 106 | })(); 107 | 108 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | imgcolr 2 | ======= 3 | 4 | imgcolr is a jQuery plugin for grabbing the dominant color of a given image's borders. You can programmably adapt the elements' color on the webpage for the image after getting the color. Based on the idea, we can make the web more beautiful and interesting. Note that imgcolr can not handle images with colorful borders properly. 5 | 6 | :point_right: [Check out the demo page](http://swaydeng.github.io/imgcolr/). 7 | 8 | ## How-To 9 | 10 | imgcolr accesses image binary data by using flash, so make sure Adobe Flash Player is installed properly. (You can also use the [HTML5 version](#vhtml5)) 11 | 12 | #### Upload SWF file 13 | 14 | First you should upload `media/imgcolr.swf` and hosts it on a server, suppose that your swf file url is `http://static.bar.com/dir/imgcolr.swf`, and all your images are hosted on the server with domain `http://img.foo.com`. 15 | 16 | #### crossdomain.xml 17 | 18 | If your swf file and images are hosted on the same domain, skip this step, if not, keep following. 19 | Make sure a `crossdomain.xml` file is in the root directory of the image server, like this: `http://img.foo.com/crossdomain.xml`, A crossdomain.xml file is an XML document that grants Adobe Flash Player(swf) permission to handle data across multiple domains ([learn more](http://www.adobe.com/cn/devnet/articles/crossdomain_policy_file_spec.html)). In this scenario, we should grants the swf on `static.bar.com` permission to access image data, so your crossdomain.xml may be like this: 20 | 21 | ```xml 22 | 23 | 24 | 25 | 26 | ``` 27 | 28 | #### JavaScript 29 | 30 | imgcolr is a jQuery plugin, so make sure jQuery is included in your web page before including imgcolr code: 31 | 32 | ```html 33 | 34 | 35 | ``` 36 | 37 | imgcolr handles `` tag, or `HTMLImageElement`, consider a page with a simple list on it: 38 | 39 | ```html 40 | 54 | ``` 55 | 56 | Now i will explain the method in action: 57 | 58 | After including **imgcolr.min.js**, a global object `Imgcolr` will be created. Before 59 | you use the plugin, you need specify the swf file's url: 60 | 61 | ```javascript 62 | Imgcolr.setSwf('http://static.bar.com/dir/imgcolr.swf'); 63 | ``` 64 | 65 | then feel free to use: 66 | 67 | ```javascript 68 | var imgs = $('img'); 69 | 70 | // get the image borders' color 71 | // and the style property background-color of each parent will be set to this color, 72 | // The result of this call is a background-color change for all div element with class "box". 73 | imgs.imgcolr(); 74 | 75 | // get the image borders' color 76 | // and the style property background-color of the ancestors with class "item" will 77 | // be set to this color. 78 | imgs.imgcolr('.item'); 79 | 80 | // get the image borders' color 81 | // you can specify which elements' background-color to set by returning them 82 | imgs.imgcolr(function () { 83 | // `this` refers to the current img element 84 | return $(this).parent().next('.label'); 85 | }); 86 | 87 | // if you don't want any element's background-color change, 88 | // or maybe you just want to know the image borders' color, 89 | // return nothing is fine. 90 | imgs.imgcolr(function (img, color) { 91 | // `img` refers to the current img element 92 | console.log(img); 93 | // `color` is the grabbed color, a string like "#ededed" 94 | console.log(color); 95 | }); 96 | 97 | // Suppose that you just adapt background color only for a given image's left and 98 | // right borders, you can ignore the others, here is the rule: 99 | // "t" represents top border 100 | // "r" represents right border 101 | // "b" represents bottom border 102 | // "l" represents left border 103 | imgs.imgcolr({ 104 | ignore: 'tb' // ignores top border and bottom border 105 | }); 106 | 107 | // Of course you can use the filter and ignore option at the same time 108 | imgs.imgcolr('.item', { 109 | ignore: 'tb' 110 | }); 111 | ``` 112 | 113 | #### AMD module support 114 | 115 | imgcolr supports AMD, the arguments are identical except that the first one is the element(s) to handle: 116 | 117 | ```javascript 118 | define(['jquery', 'imgcolr'], function ( $, Imgcolr ) { 119 | 120 | Imgcolr.setSwf('http://static.bar.com/dir/imgcolr.swf'); 121 | 122 | var imgs = $('img'); 123 | 124 | // identical to `imgs.imgcolr();` 125 | Imgcolr.imgcolr(imgs); 126 | 127 | // identical to `imgs.imgcolr('.item');` 128 | Imgcolr.imgcolr(imgs, '.item'); 129 | 130 | // identical to `imgs.imgcolr('.item', { ignore: 'tb' });` 131 | Imgcolr.imgcolr(imgs, '.item', { ignore: 'tb' }); 132 | 133 | }); 134 | ``` 135 | 136 | ## Build your own imgcolr 137 | 138 | Make sure `node` and node package `grunt-cli` are installed globally on your computer, and cd into the project directory, install necessary packages by running `npm install`. 139 | 140 | You should not modify **imgcolr.js** in root directory, for modular reason, please modify files in `src/`, and then run `grunt build` , the latest **imgcolr.js** and **imgcolr.min.js** will be created in `dist/`. 141 | 142 | ## HTML5 version 143 | 144 | I am a big fan of HTML5, however HTML5 image [CORS](https://developer.mozilla.org/en/docs/HTTP/Access_control_CORS) specification is supported terribly by browser vendors. So imgcolr based on HTML5 just supports latest modern browsers like Google Chrome and Firefox , and it is experimental. Anyway, it's really faster than the Flash version. 145 | First of all , make sure jQuery and `imgcolr.html5.min.js` are included in your web page: 146 | 147 | ```html 148 | 149 | 150 | ``` 151 | 152 | If your web page and images on the page are hosted on the same domain, skip this step, if not, you should enable image CORS by adding the appropriate Access-Control-Allow-Origin header info ([more details](https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image) you must read). 153 | 154 | There is no different on calling method, and `Imgcolr.setSwf` is unnecessary: 155 | 156 | ```javascript 157 | 158 | var imgs = $('img'); 159 | 160 | imgs.imgcolr(); 161 | 162 | ``` 163 | 164 | :point_right: [Check out the demo page](http://swaydeng.github.io/imgcolr/h5.html). -------------------------------------------------------------------------------- /imgcolr.html5.js: -------------------------------------------------------------------------------- 1 | (function (root, $) { 2 | 3 | var previousImgcolr = root.Imgcolr; 4 | 5 | var Imgcolr = {}; 6 | // all deferred objects cache 7 | var dfdCache = {}; 8 | var canvas = document.createElement('canvas'); 9 | // TODO find a better way to determine image cors support precisely. 10 | //var imgCors = !!(canvas.getContext && canvas.getContext('2d')) && $.support.cors && ('crossOrigin' in new Image()); 11 | 12 | var SIDE_TOP = 't'; 13 | var SIDE_RIGHT = 'r'; 14 | var SIDE_BOTTOM = 'b'; 15 | var SIDE_LEFT = 'l'; 16 | 17 | // get or cache Deferred objects 18 | var getDfd = function (key) { 19 | var dfd = dfdCache[key]; 20 | if (!dfd) { 21 | dfd = $.Deferred(); 22 | dfdCache[key] = dfd; 23 | } 24 | return dfd; 25 | }; 26 | 27 | var decToHex = function (num) { 28 | var hex = num.toString(16); 29 | return hex.length === 1 ? '0' + hex : hex; 30 | }; 31 | 32 | var rgbToHex = function (r, g, b) { 33 | return ['#', decToHex(r), decToHex(g), decToHex(b)].join(''); 34 | }; 35 | 36 | var count = function (idx, imageData, colorsInfo) { 37 | var name; 38 | var alpha = imageData[idx + 3]; 39 | 40 | // if true, means alpha value is less than 127, ignore this point 41 | if (alpha < 127) { 42 | return; 43 | } 44 | 45 | name = rgbToHex(imageData[idx], imageData[idx + 1], imageData[idx + 2]); 46 | if (colorsInfo[name]) { 47 | colorsInfo[name] ++; 48 | } else { 49 | colorsInfo[name] = 1; 50 | } 51 | }; 52 | 53 | var traverse = function (side, colorsInfo, width, height, imageData) { 54 | var x, y; 55 | if (side === SIDE_TOP || side === SIDE_BOTTOM) { 56 | y = (side === SIDE_TOP) ? 0 : (height - 1); 57 | for (x = 0; x < width; x ++) { 58 | count((y * width + x) * 4, imageData, colorsInfo); 59 | } 60 | } else { // side is right or left 61 | height = height - 1; 62 | x = (side === SIDE_RIGHT) ? (width - 1) : 0; 63 | for (y = 1; y < height; y ++) { 64 | count((y * width + x) * 4, imageData, colorsInfo); 65 | } 66 | } 67 | }; 68 | 69 | var computeByImage = function (img, ignore) { 70 | var data, k, v; 71 | var color = '#ffffff'; 72 | var colorAmount = 0; 73 | var colorsInfo = {}; 74 | var width = img.width; 75 | var height = img.height; 76 | var ctx = canvas.getContext('2d'); 77 | 78 | canvas.width = width; 79 | canvas.height = height; 80 | ctx.drawImage(img, 0, 0); 81 | data = ctx.getImageData(0, 0, width, height).data; 82 | 83 | if (ignore.indexOf(SIDE_TOP) < 0) { // don't ignore top border 84 | traverse(SIDE_TOP, colorsInfo, width, height, data); 85 | } 86 | if (ignore.indexOf(SIDE_RIGHT) < 0) { // don't ignore right border 87 | traverse(SIDE_RIGHT, colorsInfo, width, height, data); 88 | } 89 | if (ignore.indexOf(SIDE_BOTTOM) < 0) { // don't ignore bottom border 90 | traverse(SIDE_BOTTOM, colorsInfo, width, height, data); 91 | } 92 | if (ignore.indexOf(SIDE_LEFT) < 0) { // don't ignore left border 93 | traverse(SIDE_LEFT, colorsInfo, width, height, data); 94 | } 95 | 96 | for (k in colorsInfo) { 97 | v = colorsInfo[k]; 98 | if (v > colorAmount) { 99 | color = k; 100 | colorAmount = v; 101 | } 102 | } 103 | 104 | return color; 105 | }; 106 | 107 | var compute = function (url, ignore) { 108 | var img = new Image(); 109 | var data = { url: url, ignore: ignore }; 110 | 111 | img.onload = function () { 112 | try { 113 | data.color = computeByImage(this, ignore); 114 | getDfd(url).resolve(data); 115 | } catch (e) { // Error - the canvas has been tainted by cross-origin data. 116 | getDfd(url).reject(data); 117 | } 118 | img = null; 119 | }; 120 | img.onerror = function () { // Error - Cross-origin image load denied 121 | img.onerror = null; 122 | img = null; 123 | getDfd(url).reject(data); 124 | }; 125 | 126 | img.crossOrigin = ''; // '' is same as 'anonymous' 127 | img.src = url; 128 | }; 129 | 130 | // Imgcolr.color 131 | // ---------------- core method --------------- 132 | // @param {string} options.url - The url of the image 133 | // @param {string} options.ignore - Which border should be ignored, 134 | // there are 4 kinds of values: 't', 'r', 'b', 'l', you can ignore multiple borders like this: 'tb', it's optional 135 | // @param {function} options.success - The callback for success 136 | // @param {function} options.error - The callback for error, it's optional 137 | Imgcolr.color = function (options) { 138 | var dfd = getDfd(options.url); 139 | 140 | if (typeof options.success === 'function') { 141 | dfd.done(options.success); 142 | } 143 | 144 | if (typeof options.error === 'function') { 145 | dfd.fail(options.error); 146 | } 147 | 148 | if ('pending' === dfd.state()) { 149 | compute(options.url, typeof options.ignore === 'string' ? options.ignore : ''); 150 | } 151 | }; 152 | 153 | Imgcolr.noConflict = function () { 154 | root.Imgcolr = previousImgcolr; 155 | return Imgcolr; 156 | }; 157 | 158 | root.Imgcolr = Imgcolr; 159 | 160 | // jQuery Plugin extend - for example: $(elem).imgcolr() 161 | var pluginName = 'imgcolr'; 162 | 163 | function Plugin (element, selector, options) { 164 | var elem = $(element); 165 | var ignore = elem.data('imgcolrIgnore'); 166 | var defOpt = { 167 | url: element.src 168 | }; 169 | 170 | if (typeof selector === 'object') { 171 | options = selector; 172 | selector = undefined; 173 | } 174 | 175 | options = $.extend(defOpt, options); 176 | // if data-imgcolr-ignore is specified on the img node, then rewrite the options 177 | if (typeof ignore === 'string') { 178 | options.ignore = ignore; 179 | } 180 | 181 | options.success = function (data) { 182 | var matches = typeof selector === 'function' ? selector.call(element, element, data.color) : 183 | typeof selector === 'string' ? elem.parents(selector) : elem.parent(); 184 | // for `selector.call(element, element, data.color)` may not return a jQuery object 185 | if (matches && matches.jquery) { 186 | matches.css('backgroundColor', data.color); 187 | } 188 | }; 189 | 190 | Imgcolr.color(options); 191 | } 192 | 193 | // @param selector {Selector | Function}[optional] 194 | // @param {string} options.ignore - Which border should be ignored, 195 | // there are 4 kinds of values: 't', 'r', 'b', 'l', you can ignore multiple borders like this: 'tb', it's optional 196 | $.fn[pluginName] = function (selector, options) { 197 | return this.each(function () { 198 | new Plugin(this, selector, options); 199 | }); 200 | }; 201 | 202 | })(this, jQuery); -------------------------------------------------------------------------------- /as_src/Imgcolr.as: -------------------------------------------------------------------------------- 1 | package 2 | { 3 | 4 | 5 | import flash.display.Bitmap; 6 | import flash.display.BitmapData; 7 | import flash.display.Sprite; 8 | import flash.events.Event; 9 | import flash.events.HTTPStatusEvent; 10 | import flash.external.ExternalInterface; 11 | import flash.net.URLRequest; 12 | import flash.system.LoaderContext; 13 | import flash.system.Security; 14 | import flash.utils.setTimeout; 15 | 16 | 17 | /** 18 | * A tool for getting the border color of an image. 19 | * @author Sway Deng 20 | * Document Class 21 | */ 22 | public class Imgcolr extends Sprite { 23 | 24 | //-------------------------------------------------------------------------- 25 | // Private global constants which represent border side 26 | //-------------------------------------------------------------------------- 27 | private const SIDE_TOP:String = 't'; // top 28 | private const SIDE_RIGHT:String = 'r'; // right 29 | private const SIDE_BOTTOM:String = 'b'; // bottom 30 | private const SIDE_LEFT:String = 'l'; // left 31 | private const JS_EVENT_TRIGGER:String = 'Imgcolr.trigger'; 32 | private const JS_ACCESSOR:String = 'getColor'; // js can use this as the accessor 33 | 34 | //-------------------------------------------------------------------------- 35 | // Private global variables 36 | //-------------------------------------------------------------------------- 37 | private var _loaderCtx:LoaderContext; 38 | private var _eventTrigger:String = JS_EVENT_TRIGGER; 39 | 40 | public function Imgcolr () { 41 | setTimeout(function ():void { 42 | 43 | var paramObj:Object = root.loaderInfo.parameters; 44 | var allowedDomain:String = paramObj.allowedDomain || null; 45 | var eventHandler:String = paramObj.eventHandler || null; 46 | 47 | _loaderCtx = new LoaderContext(true); 48 | 49 | if (allowedDomain) { 50 | Security.allowDomain(allowedDomain); 51 | } 52 | if (eventHandler) { 53 | _eventTrigger = eventHandler; 54 | } 55 | // register the external interface 56 | ExternalInterface.addCallback(JS_ACCESSOR, getColor); 57 | // tell JS that swf is ready 58 | dispatchEventToJavascript( { type:'swfReady' } ); 59 | 60 | }, 500); 61 | } 62 | 63 | private function getColor (url:String, ignore:String=''):void { 64 | var ldr:ImageLoader = new ImageLoader(ignore); 65 | var fileRequest:URLRequest = new URLRequest(url); 66 | 67 | ldr.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); 68 | ldr.load(fileRequest, _loaderCtx); 69 | } 70 | 71 | private function onLoadComplete (evt:Event):void { 72 | var targetLdr:ImageLoader = evt.currentTarget.loader; 73 | var ignore:String = targetLdr.ignore; 74 | var url:String = targetLdr.contentLoaderInfo.url; 75 | var data:Object = { }; 76 | data.url = url; 77 | data.ignore = ignore; 78 | try { 79 | var bm:Bitmap = Bitmap(targetLdr.content); 80 | var bmd:BitmapData = bm.bitmapData; 81 | var color:String = getBorderColor(bmd, ignore); 82 | data.color = color; 83 | // Got the dominant color of the loaded image's border 84 | dispatchEventToJavascript({ type:'success', data: data }); 85 | } catch (error:Error) { 86 | data.errorMsg = error.name; 87 | dispatchEventToJavascript({ type:'error', data: data }); 88 | } 89 | } 90 | 91 | /** 92 | * Broadcast an event to JS 93 | * @param evtObj { type: 'eventType', data: {} } 94 | */ 95 | private function dispatchEventToJavascript (evtObj:Object):void { 96 | if (ExternalInterface.available) { 97 | ExternalInterface.call(_eventTrigger, evtObj); 98 | } 99 | } 100 | 101 | ///========================================================================================================================== 102 | 103 | /** 104 | * Get the dominant color of an image's border 105 | * 106 | * @param bmd The image's bitmapData 107 | * @param ignore Which border should be ignored, there are 4 kinds of values: 't', 'r', 'b', 'l' 108 | * @return The dominant color of an image's border 109 | * 110 | */ 111 | public function getBorderColor (bmd:BitmapData, ignore:String = ''):String { 112 | var mainColorNum:uint = 0; 113 | var mainColor:String = '#ffffff'; 114 | 115 | var colors:Object = {}; 116 | 117 | bmd.lock(); 118 | 119 | if (ignore.indexOf(SIDE_TOP) < 0) { // don't ignore top border 120 | traverse(bmd, SIDE_TOP, colors); 121 | } 122 | if (ignore.indexOf(SIDE_RIGHT) < 0) { // don't ignore right border 123 | traverse(bmd, SIDE_RIGHT, colors); 124 | } 125 | if (ignore.indexOf(SIDE_BOTTOM) < 0) { // don't ignore bottom border 126 | traverse(bmd, SIDE_BOTTOM, colors); 127 | } 128 | if (ignore.indexOf(SIDE_LEFT) < 0) { // don't ignore left border 129 | traverse(bmd, SIDE_LEFT, colors); 130 | } 131 | 132 | bmd.unlock(); 133 | 134 | for (var k:String in colors) { 135 | var v:uint = colors[k]; 136 | if (v > mainColorNum) { 137 | mainColor = k; 138 | mainColorNum = v; 139 | } 140 | } 141 | 142 | return mainColor; 143 | } 144 | /** 145 | * Traverse the specified border's color 146 | * 147 | * @param bmd The image's bitmapData 148 | * @param side The specified border to traverse 149 | * @param colors the JSON Object that is used for storing colors' amount 150 | * 151 | */ 152 | private function traverse (bmd:BitmapData, side:String, colors:Object):void { 153 | var x:uint; 154 | var y:uint; 155 | var len:uint; 156 | var width:uint = bmd.width; 157 | var height:uint = bmd.height; 158 | 159 | if (side === SIDE_TOP || side === SIDE_BOTTOM) { // side top or bottom 160 | y = (side == SIDE_TOP) ? 0 : (height - 1); 161 | for (x = 0; x < width; x++) { 162 | countColor(bmd, x, y, colors); 163 | } 164 | } else { // side right or left 165 | x = (side == SIDE_RIGHT) ? (width - 1) : 0; 166 | len = height - 1; 167 | for (y = 1; y < len; y++) { 168 | countColor(bmd, x, y, colors); 169 | } 170 | } 171 | } 172 | 173 | // Count the specified point's color 174 | private function countColor (bmd:BitmapData, x:uint, y:uint, colors:Object):void { 175 | var argb:uint = bmd.getPixel32(x, y); 176 | var alpha:uint = (argb >> 24 & 0xFF); 177 | 178 | if (alpha < 0x7f) return; // if true, means alpha value is less than 127, ignore this point 179 | 180 | var hexColor:String = '#' + argb.toString(16).slice(2); // e.g. 0xff33eedd -> 33eedd 181 | 182 | if (colors[hexColor]) { 183 | colors[hexColor] ++; 184 | } else { 185 | colors[hexColor] = 1; 186 | } 187 | } 188 | } 189 | } -------------------------------------------------------------------------------- /imgcolr.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * imgcolr v1.0.1 3 | * Author: Sway Deng 4 | * Released under the MIT license 5 | */ 6 | (function (window, $, undefined) { 7 | // shortcut for Imgcolr 8 | var Imgcolr = {}; 9 | 10 | 11 | 12 | /****** some constants ******/ 13 | // event name 14 | var EVT_SWFREADY = 'swfReady'; 15 | var EVT_SUCCESS = 'success'; 16 | var EVT_ERROR = 'error'; 17 | // swf dfd keyname 18 | var DFD_SWF = 'dfd-swf'; 19 | 20 | // swf file url, swf object 21 | var swfUrl, swfObj; 22 | // all deferred objects cache 23 | var dfdCache = {}; 24 | // get or cache Deferred objects 25 | var getDfd = function (key) { 26 | var dfd = dfdCache[key]; 27 | if (!dfd) { 28 | dfd = $.Deferred(); 29 | dfdCache[key] = dfd; 30 | } 31 | return dfd; 32 | }; 33 | 34 | // swf method 35 | var compute = function (url, ignore) { 36 | var style = 'position:absolute; left:0; top:0; width:1px; height:1px;'; 37 | var swfNode = $('
').appendTo('body'); 38 | 39 | swfObj = appendFlash(swfNode, { 40 | width: 1, 41 | height: 1, 42 | wmode: 'transparent', 43 | swf: swfUrl, 44 | allowScriptAccess: 'always', 45 | flashvars: { 46 | allowedDomain: window.location.hostname 47 | } 48 | }); 49 | 50 | compute = function (url, ignore) { 51 | getDfd(DFD_SWF).done(function (obj) { 52 | obj.getColor(url, ignore); 53 | }); 54 | }; 55 | 56 | compute(url, ignore); 57 | }; 58 | // You must specify the swf url according to your scenario before using this. 59 | Imgcolr.setSwf = function (url) { 60 | swfUrl = url; 61 | }; 62 | 63 | Imgcolr.getSwf = function () { 64 | return swfUrl; 65 | }; 66 | 67 | // @private - very important, this method is called from swf internally 68 | Imgcolr.trigger = function (evtObj) { 69 | switch (evtObj.type) { 70 | case EVT_SWFREADY: 71 | getDfd(DFD_SWF).resolve(swfObj); 72 | break; 73 | case EVT_SUCCESS: 74 | getDfd(evtObj.data.url).resolve(evtObj.data); 75 | break; 76 | case EVT_ERROR: 77 | getDfd(evtObj.data.url).reject(evtObj.data); 78 | break; 79 | } 80 | }; 81 | // Imgcolr.color 82 | // ---------------- core method --------------- 83 | // @param {string} options.url - The url of the image 84 | // @param {string} options.ignore - Which border should be ignored, 85 | // there are 4 kinds of values: 't', 'r', 'b', 'l', you can ignore multiple borders like this: 'tb', it's optional 86 | // @param {function} options.success - The callback for success 87 | // @param {function} options.error - The callback for error, it's optional 88 | Imgcolr.color = function (options) { 89 | var dfd = getDfd(options.url); 90 | 91 | if (typeof options.success === 'function') { 92 | dfd.done(options.success); 93 | } 94 | 95 | if (typeof options.error === 'function') { 96 | dfd.fail(options.error); 97 | } 98 | 99 | if ('pending' === dfd.state()) { 100 | compute(options.url, typeof options.ignore === 'string' ? options.ignore : ''); 101 | } 102 | }; 103 | 104 | 105 | 106 | 107 | var appendFlash = (function () { 108 | var version, versionNumbers, flashAvailable; 109 | // Prototype style 110 | // https://github.com/sstephenson/prototype/blob/1fb9728/src/prototype.js#L81 111 | var isIE = !!window.attachEvent && Object.prototype.toString.call(window.opera) !== '[object Opera]'; 112 | 113 | var Plugin = navigator.plugins['Shockwave Flash'] || window.ActiveXObject; 114 | 115 | try { 116 | if (Plugin.description) { 117 | version = Plugin.description; 118 | } else { 119 | version = (new Plugin('ShockwaveFlash.ShockwaveFlash')).GetVariable('$version'); 120 | } 121 | } catch (e) { 122 | version = 'Unavailable'; 123 | } 124 | versionNumbers = version.match(/\d+/g); 125 | flashAvailable = !!versionNumbers && versionNumbers[0] > 0; 126 | 127 | function buildQueryString (obj) { 128 | if (!$.isPlainObject(obj)) { 129 | return obj; 130 | } 131 | 132 | var k, v; 133 | var arr = []; 134 | var str = ''; 135 | 136 | for (k in obj) { 137 | v = obj[k]; 138 | if ($.isPlainObject(v)) { 139 | str = buildQueryString(v); 140 | } else { 141 | str = [k, encodeURI(v)].join('='); 142 | } 143 | arr.push(str); 144 | } 145 | 146 | return arr.join('&'); 147 | } 148 | 149 | // build attributes based on an object 150 | function buildAttr (obj) { 151 | var k, v; 152 | var arr = []; 153 | 154 | for (k in obj) { 155 | v = obj[k]; 156 | if (v) { 157 | arr.push([k, '="', v, '"'].join('')); 158 | } 159 | } 160 | 161 | return arr.join(' '); 162 | } 163 | 164 | function buildParamTag (obj) { 165 | var arr = []; 166 | 167 | for (var k in obj) { 168 | arr.push([''].join('')); 169 | } 170 | 171 | return arr.join(''); 172 | } 173 | 174 | // return the real method to append a flash object 175 | return function (elem, options) { 176 | var attrs; 177 | 178 | if (!options.swf || !flashAvailable) { 179 | return false; 180 | } 181 | 182 | attrs = { 183 | id: 'swf-' + ($.guid++), 184 | width: options.width || 1, 185 | height: options.height || 1, 186 | style: options.style || '' 187 | }; 188 | 189 | if (isIE) { 190 | attrs.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000'; 191 | options.movie = options.swf; 192 | } else { 193 | attrs.data = options.swf; 194 | attrs.type = 'application/x-shockwave-flash'; 195 | } 196 | 197 | options.wmode = options.wmode || 'opaque'; 198 | 199 | var html = ['', buildParamTag(options), ''].join(''); 200 | if (isIE) { 201 | var flashContainer = document.createElement('div'); 202 | elem.html(flashContainer); 203 | flashContainer.outerHTML = html; 204 | } else { 205 | elem.html(html); 206 | } 207 | 208 | return elem.children().get(0); 209 | }; 210 | })(); 211 | 212 | 213 | 214 | 215 | // The top-level namespace, so that so that the method Imgcolr.color can be invoked from swf 216 | window.Imgcolr = Imgcolr; 217 | 218 | 219 | 220 | 221 | // jQuery Plugin - for example: $(elem).imgcolr() 222 | var pluginName = 'imgcolr'; 223 | 224 | function Plugin (element, selector, options) { 225 | var elem = $(element); 226 | var ignore = elem.data('imgcolrIgnore'); 227 | var defOpt = { 228 | url: element.src 229 | }; 230 | 231 | if (typeof selector === 'object') { 232 | options = selector; 233 | selector = undefined; 234 | } 235 | 236 | options = $.extend(defOpt, options); 237 | // if data-imgcolr-ignore is specified on the img node, then rewrite the options 238 | if (typeof ignore === 'string') { 239 | options.ignore = ignore; 240 | } 241 | 242 | options.success = function (data) { 243 | var matches = typeof selector === 'function' ? selector.call(element, element, data.color) : 244 | typeof selector === 'string' ? elem.parents(selector) : elem.parent(); 245 | // for `selector.call(element, element, data.color)` may not return a jQuery object 246 | if (matches && matches.jquery) { 247 | matches.css('backgroundColor', data.color); 248 | } 249 | }; 250 | 251 | Imgcolr.color(options); 252 | } 253 | 254 | // @param selector {Selector | Function}[optional] 255 | // @param {string} options.ignore - Which border should be ignored, 256 | // there are 4 kinds of values: 't', 'r', 'b', 'l', you can ignore multiple borders like this: 'tb', it's optional 257 | $.fn[pluginName] = function (selector, options) { 258 | return this.each(function () { 259 | new Plugin(this, selector, options); 260 | }); 261 | }; 262 | 263 | 264 | 265 | 266 | // AMD module support 267 | Imgcolr.imgcolr = function (elem, selector, options) { 268 | $(elem).imgcolr(selector, options); 269 | }; 270 | 271 | if (typeof define === 'function' && define.amd) { 272 | define('imgcolr', [], function () { return Imgcolr; }); 273 | } 274 | 275 | })(window, jQuery); --------------------------------------------------------------------------------