├── AUTHORS ├── res └── img │ ├── 1.jpg │ ├── 2.jpg │ ├── 3.jpg │ ├── 4.jpg │ ├── 5.jpg │ ├── 7.jpg │ ├── 8.jpg │ ├── y.jpg │ ├── 10.jpg │ ├── 11.jpg │ ├── 12.jpg │ ├── Yuv3.jpg │ ├── yuv2.jpg │ └── yuv4.jpg ├── doc └── AI规范.md ├── test ├── test.html ├── testRect.html ├── testTransform.html ├── denoise.html ├── testWidth.html ├── testDefine.html ├── save.html ├── test2.html ├── testnew.html ├── testSeletiveColor.html ├── testTools.html └── testView.html ├── nsrc ├── alloyimage.info.js ├── alloyimage.util.js ├── alloyimage.define.js ├── alloyimage.fix.js ├── alloyimage.config.js ├── alloyimage.process.js ├── alloyimage.layer.js └── alloyimage.base.js ├── src ├── module │ ├── filter │ │ ├── toReverse.js │ │ ├── toGray.js │ │ ├── toThresh.js │ │ ├── lapOfGauss.js │ │ ├── ImageEnhance.js │ │ ├── sepia.js │ │ ├── noise.js │ │ ├── sharp.js │ │ ├── corrode.js │ │ ├── oilPainting.js │ │ ├── posterize.js │ │ ├── embossment.js │ │ ├── mosaic.js │ │ ├── darkCorner.js │ │ ├── dotted.js │ │ └── gaussBlur.js │ ├── alteration │ │ ├── brightness.js │ │ ├── gamma.js │ │ ├── setHSI.js │ │ ├── curve.js │ │ └── seletiveColor.js │ ├── fix.js │ ├── applyMatrix.js │ ├── config.js │ ├── easy.js │ ├── dorsyWorker.js │ ├── tools.js │ ├── addLayer.js │ └── dorsyMath.js └── other │ ├── LICENSE.md │ └── binaryajax.js ├── .gitignore ├── demo ├── demo3.html ├── demo4.html ├── demo2.html ├── demo5.html ├── demo1.html └── index.html ├── LICENSE ├── README.md └── release └── alloyimage-1.1.js /AUTHORS: -------------------------------------------------------------------------------- 1 | --AUTHORS-- 2 | 3 | -------------------------------------------------------------------------------- /res/img/1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/1.jpg -------------------------------------------------------------------------------- /res/img/2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/2.jpg -------------------------------------------------------------------------------- /res/img/3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/3.jpg -------------------------------------------------------------------------------- /res/img/4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/4.jpg -------------------------------------------------------------------------------- /res/img/5.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/5.jpg -------------------------------------------------------------------------------- /res/img/7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/7.jpg -------------------------------------------------------------------------------- /res/img/8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/8.jpg -------------------------------------------------------------------------------- /res/img/y.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/y.jpg -------------------------------------------------------------------------------- /res/img/10.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/10.jpg -------------------------------------------------------------------------------- /res/img/11.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/11.jpg -------------------------------------------------------------------------------- /res/img/12.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/12.jpg -------------------------------------------------------------------------------- /res/img/Yuv3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/Yuv3.jpg -------------------------------------------------------------------------------- /res/img/yuv2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/yuv2.jpg -------------------------------------------------------------------------------- /res/img/yuv4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/AlloyTeam/AlloyImage/HEAD/res/img/yuv4.jpg -------------------------------------------------------------------------------- /doc/AI规范.md: -------------------------------------------------------------------------------- 1 | # 代码编写的一些原则 2 | ### 主处理对象保持单例、私有的,且不能与DOM交互 3 | ### 内部保持清晰逻辑体系,可以更复杂架构以达到清晰分类,外部接口始终保持单一、简单 4 | ### 滤镜Filter模块相互之间不能调用 5 | -------------------------------------------------------------------------------- /test/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /test/testRect.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/testTransform.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /nsrc/alloyimage.info.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlloyImage info module 3 | * something about AlloyImage 4 | * @author dorsywang From Tencent AlloyTeam 5 | */ 6 | 7 | AIDefine('info', [], function(){ 8 | var Info = { 9 | VERSION: "1.0.0", 10 | AUTHOR: "dorsywang", 11 | EMAIL: "314416946@qq.com", 12 | BLOG: "http://www.dorsywang.com", 13 | TEAM: "Tencent.AlloyTeam", 14 | TEAM_BLOG: "http://www.alloyteam.com" 15 | }; 16 | 17 | AIExport.put('info', Info); 18 | 19 | return Info; 20 | }); 21 | -------------------------------------------------------------------------------- /test/denoise.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /test/testWidth.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /test/testDefine.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /test/save.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /src/module/filter/toReverse.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 反色 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.toReverse",function(P){ 9 | 10 | var M = { 11 | process: function(imgData){ 12 | var data = imgData.data; 13 | 14 | for(var i = 0,n = data.length;i < n;i += 4){ 15 | data[i] = 255 - data[i]; 16 | data[i + 1] = 255 - data[i + 1]; 17 | data[i + 2] = 255 - data[i + 2]; 18 | } 19 | 20 | imgData.data = data; 21 | 22 | return imgData; 23 | } 24 | }; 25 | 26 | return M; 27 | 28 | }); 29 | 30 | })("psLib"); 31 | -------------------------------------------------------------------------------- /src/module/filter/toGray.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 灰度处理 4 | * @modify: 灰度算法改成加权平均值 (0.299, 0.578, 0.114) 5 | * 6 | */ 7 | ;(function(Ps){ 8 | 9 | window[Ps].module("Filter.toGray",function(P){ 10 | 11 | var M = { 12 | process: function(imgData){ 13 | var data = imgData.data; 14 | 15 | for(var i = 0,n = data.length;i < n;i += 4){ 16 | var gray = parseInt((0.299 * data[i] + 0.578 * data[i + 1] + 0.114 * data[i + 2])); 17 | data[i + 2] = data[i + 1] = data[i] = gray; 18 | } 19 | 20 | imgData.data = data; 21 | 22 | return imgData; 23 | } 24 | }; 25 | 26 | return M; 27 | 28 | }); 29 | 30 | })("psLib"); 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Include your project-specific ignores in this file 2 | # Read about how to use .gitignore: https://help.github.com/articles/ignoring-files 3 | 4 | # Numerous always-ignore extensions 5 | *.diff 6 | *.err 7 | *.orig 8 | *.log 9 | *.rej 10 | *.swo 11 | *.swp 12 | *.vi 13 | *~ 14 | *.sass-cache 15 | 16 | # OS or Editor folders 17 | .DS_Store 18 | ._* 19 | Thumbs.db 20 | .cache 21 | .project 22 | .settings 23 | .tmproj 24 | nbproject 25 | *.sublime-project 26 | *.sublime-workspace 27 | 28 | # Dreamweaver added files 29 | _notes 30 | dwsync.xml 31 | 32 | # Komodo 33 | *.komodoproject 34 | .komodotools 35 | 36 | # Espresso 37 | *.esproj 38 | *.espressostorage 39 | 40 | # Rubinius 41 | *.rbc 42 | 43 | # Folders to ignore 44 | .hg 45 | .svn 46 | .CVS 47 | intermediate 48 | publish 49 | .idea 50 | 51 | -------------------------------------------------------------------------------- /src/module/filter/toThresh.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description:灰度阈值 做只有2级灰度图像处理 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.toThresh",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){ 12 | imgData = P.reflect("toGray", imgData); 13 | var data = imgData.data; 14 | 15 | var arg = arg[0] || 128; 16 | for(var i = 0,n = data.length;i < n;i ++){ 17 | if((i + 1) % 4){ 18 | data[i] = data[i] > arg ? 255 : 0; 19 | } 20 | } 21 | 22 | imgData.data = data; 23 | 24 | return imgData; 25 | } 26 | }; 27 | 28 | return M; 29 | 30 | }); 31 | 32 | })("psLib"); 33 | -------------------------------------------------------------------------------- /test/test2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /demo/demo3.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlloyPhoto Demo1 6 | 10 | 11 | 12 | 13 | 14 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /nsrc/alloyimage.util.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlloyImage util module 3 | * @author dorsywang From Tencent AlloyTeam 4 | */ 5 | 6 | AIDefine('util', [], function(){ 7 | var Util = { 8 | getDevice: function(){ 9 | var device; 10 | 11 | if(window.navigator){ 12 | var ua = window.navigator.userAgent; 13 | 14 | if(/Android|android/.test(ua)){ 15 | device = 'android'; 16 | }else if(/iPhone|iPad|iPod/.test(ua)){ 17 | device = 'ios'; 18 | }else{ 19 | device = 'other'; 20 | } 21 | }else{ 22 | device = "sandBox"; 23 | } 24 | 25 | return function(){ 26 | return device; 27 | }; 28 | }() 29 | }; 30 | 31 | return Util; 32 | }); 33 | -------------------------------------------------------------------------------- /test/testnew.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /demo/demo4.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlloyPhoto Demo1 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /src/module/filter/lapOfGauss.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 查找边缘 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.borderline",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){ 12 | var template1 = [ 13 | -2,-4,-4,-4,-2, 14 | -4,0,8,0,-4, 15 | -4,8,24,8,-4, 16 | -4,0,8,0,-4, 17 | -2,-4,-4,-4,-2 18 | ]; 19 | var template2 = [ 20 | 0, 1, 0, 21 | 1, -4, 1, 22 | 0, 1, 0 23 | ]; 24 | var template3 = [ 25 | ]; 26 | return P.lib.dorsyMath.applyMatrix(imgData,template2,250); 27 | } 28 | }; 29 | 30 | return M; 31 | 32 | }); 33 | 34 | })("psLib"); 35 | -------------------------------------------------------------------------------- /src/module/filter/ImageEnhance.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description:灰度扩展 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.ImageEnhance",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg1,arg2){ 12 | var lamta = arg || 0.5; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | var p1 = arg1 || {x: 10,y: 10}; 17 | var p2 = arg2 || {x: 50,y: 40}; 18 | 19 | function transfer(d){ 20 | } 21 | 22 | for(var i = 0,n = data.length;i < n;i += 4){ 23 | 24 | } 25 | 26 | imgData.data = data; 27 | 28 | return imgData; 29 | } 30 | }; 31 | 32 | return M; 33 | 34 | }); 35 | 36 | })("psLib"); 37 | -------------------------------------------------------------------------------- /src/module/alteration/brightness.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 调整亮度对比度 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Alteration.brightness",function(P){ 9 | 10 | var M = { 11 | //调节亮度对比度 12 | process: function(imgData, args){ 13 | var data = imgData.data; 14 | var brightness = args[0] / 50;// -1,1 15 | var arg2 = args[1] || 0; 16 | var c = arg2 / 50;// -1,1 17 | var k = Math.tan((45 + 44 * c) * Math.PI / 180); 18 | 19 | for(var i = 0,n = data.length;i < n;i += 4){ 20 | for(var j = 0;j < 3;j ++){ 21 | data[i + j] = (data[i + j] - 127.5 * (1 - brightness)) * k + 127.5 * (1 + brightness); 22 | } 23 | } 24 | 25 | return imgData; 26 | } 27 | }; 28 | 29 | return M; 30 | 31 | }); 32 | 33 | })("psLib"); 34 | -------------------------------------------------------------------------------- /demo/demo2.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlloyPhoto Demo1 6 | 10 | 11 | 12 | 13 | 14 | 15 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /demo/demo5.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlloyPhoto Demo1 亮白 6 | 10 | 11 | 12 | 13 | 14 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /test/testSeletiveColor.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /src/module/filter/sepia.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 棕褐色 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.sepia",function(P){ 9 | 10 | var M = { 11 | process: function(imgData){ 12 | var dM = P.lib.dorsyMath; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | 17 | for(var x = 0; x < width; x ++){ 18 | for(var y = 0; y < height; y ++){ 19 | dM.xyCal(imgData, x, y, function(r, g, b){ 20 | return [ 21 | r * 0.393 + g * 0.769 + b * 0.189, 22 | r * 0.349 + g * 0.686 + b * 0.168, 23 | r * 0.272 + g * 0.534 + b * 0.131 24 | ]; 25 | }); 26 | } 27 | } 28 | return imgData; 29 | } 30 | }; 31 | 32 | return M; 33 | 34 | }); 35 | 36 | })("psLib"); 37 | -------------------------------------------------------------------------------- /src/module/filter/noise.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 添加杂色 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.noise",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){ 12 | var R = parseInt(arg[0]) || 100; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | var xLength = R * 2 + 1; 17 | 18 | //区块 19 | for(var x = 0;x < width;x ++){ 20 | 21 | for(var y = 0;y < height;y ++){ 22 | 23 | var realI = y * width + x; 24 | for(var j = 0;j < 3;j ++){ 25 | var rand = parseInt(Math.random() * R * 2) - R; 26 | data[realI * 4 + j] += rand; 27 | } 28 | 29 | } 30 | 31 | } 32 | 33 | 34 | return imgData; 35 | } 36 | }; 37 | 38 | return M; 39 | 40 | }); 41 | 42 | })("psLib"); 43 | -------------------------------------------------------------------------------- /src/other/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2008 Jacob Seidelin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. -------------------------------------------------------------------------------- /demo/demo1.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | AlloyPhoto Demo1 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 腾讯 AlloyTeam 4 | http://www.alloyteam.com 5 | http://alloyteam.github.io/ 6 | 7 | Permission is hereby granted, free of charge, to any person obtaining 8 | a copy of this software and associated documentation files (the 9 | "Software"), to deal in the Software without restriction, including 10 | without limitation the rights to use, copy, modify, merge, publish, 11 | distribute, sublicense, and/or sell copies of the Software, and to 12 | permit persons to whom the Software is furnished to do so, subject to 13 | the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be 16 | included in all copies or substantial portions of the Software. 17 | 18 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 22 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 23 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 24 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 25 | -------------------------------------------------------------------------------- /test/testTools.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /src/module/filter/sharp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description:锐化 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.sharp",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){ 12 | var lamta = arg[0] || 0.6; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | 17 | for(var i = 0,n = data.length;i < n;i += 4){ 18 | var ii = i / 4; 19 | var row = parseInt(ii / width); 20 | var col = ii % width; 21 | if(row == 0 || col == 0) continue; 22 | 23 | var A = ((row - 1) * width + (col - 1)) * 4; 24 | var B = ((row - 1) * width + col) * 4; 25 | var E = (ii - 1) * 4; 26 | 27 | for(var j = 0;j < 3;j ++){ 28 | var delta = data[i + j] - (data[B + j] + data[E + j] + data[A + j]) / 3; 29 | data[i + j] += delta * lamta; 30 | } 31 | } 32 | 33 | return imgData; 34 | } 35 | }; 36 | 37 | return M; 38 | 39 | }); 40 | 41 | })("psLib"); 42 | -------------------------------------------------------------------------------- /src/module/filter/corrode.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 腐蚀 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.corrode", function(P){ 9 | 10 | var M = { 11 | process: function(imgData, arg){ 12 | var R = parseInt(arg[0]) || 3; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | var xLength = R * 2 + 1; 17 | 18 | //区块 19 | for(var x = 0; x < width; x ++){ 20 | 21 | for(var y = 0; y < height; y ++){ 22 | 23 | var randomI = parseInt(Math.random() * R * 2) - R ;//区块随机代表 24 | var randomJ = parseInt(Math.random() * R * 2) - R;//区块随机代表 25 | var realI = y * width + x; 26 | var realJ = (y + randomI) * width + x + randomJ; 27 | 28 | for(var j = 0; j < 3; j ++){ 29 | data[realI * 4 + j] = data[realJ * 4 + j]; 30 | } 31 | 32 | } 33 | 34 | } 35 | 36 | return imgData; 37 | } 38 | }; 39 | 40 | return M; 41 | 42 | }); 43 | 44 | })("psLib"); 45 | -------------------------------------------------------------------------------- /src/module/filter/oilPainting.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 油画 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.oilPainting",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){ 12 | var R = parseInt(arg[0]) || 16; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | var xLength = R * 2 + 1; 17 | 18 | //区块 19 | for(var x = 0;x < width;x ++){ 20 | 21 | for(var y = 0;y < height;y ++){ 22 | 23 | var realI = y * width + x; 24 | var gray = 0; 25 | for(var j = 0;j < 3;j ++){ 26 | gray += data[realI * 4 + j]; 27 | } 28 | gray = gray / 3; 29 | var every = parseInt(gray / R) * R; 30 | for(var j = 0;j < 3;j ++){ 31 | data[realI * 4 + j] = every; 32 | } 33 | } 34 | 35 | } 36 | 37 | 38 | return imgData; 39 | } 40 | }; 41 | 42 | return M; 43 | 44 | }); 45 | 46 | })("psLib"); 47 | -------------------------------------------------------------------------------- /src/module/alteration/gamma.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: gamma调节 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Alteration.gamma",function(P){ 9 | 10 | var M = { 11 | process: function(imgData, args){ 12 | var dM = P.lib.dorsyMath; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | 17 | //gamma阶-100, 100 18 | var gamma; 19 | 20 | if(args[0] == undefined) gamma = 10; 21 | else gamma = args[0]; 22 | 23 | var normalizedArg = ((gamma + 100) / 200) * 2; 24 | 25 | for(var x = 0; x < width; x ++){ 26 | for(var y = 0; y < height; y ++){ 27 | dM.xyCal(imgData, x, y, function(r, g, b){ 28 | return [ 29 | Math.pow(r, normalizedArg), 30 | Math.pow(g, normalizedArg), 31 | Math.pow(b, normalizedArg) 32 | ]; 33 | }); 34 | } 35 | } 36 | return imgData; 37 | } 38 | }; 39 | 40 | return M; 41 | 42 | }); 43 | 44 | })("psLib"); 45 | -------------------------------------------------------------------------------- /src/module/filter/posterize.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 色调分离 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.posterize",function(P){ 9 | 10 | var M = { 11 | process: function(imgData, args){ 12 | var dM = P.lib.dorsyMath; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | 17 | //灰度阶数 18 | //由原来的255阶映射为现在的阶数 19 | var step = args[0] || 20; 20 | 21 | step = step < 1 ? 1 : (step > 255 ? 255 : step); 22 | var level = Math.floor(255 / step); 23 | 24 | for(var x = 0; x < width; x ++){ 25 | for(var y = 0; y < height; y ++){ 26 | dM.xyCal(imgData, x, y, function(r, g, b){ 27 | return [ 28 | Math.floor(r / level) * level, 29 | Math.floor(g / level) * level, 30 | Math.floor(b / level) * level 31 | ]; 32 | }); 33 | } 34 | } 35 | return imgData; 36 | } 37 | }; 38 | 39 | return M; 40 | 41 | }); 42 | 43 | })("psLib"); 44 | -------------------------------------------------------------------------------- /src/module/filter/embossment.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 浮雕效果 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.embossment",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){//调节亮度对比度 12 | var data = imgData.data; 13 | var width = imgData.width; 14 | var height = imgData.height; 15 | 16 | var outData = []; 17 | for(var i = 0,n = data.length;i < n;i += 4){ 18 | 19 | var ii = i / 4; 20 | var row = parseInt(ii / width); 21 | var col = ii % width; 22 | var A = ((row - 1) * width + (col - 1)) * 4; 23 | var G = (row + 1) * width * 4 + (col + 1) * 4; 24 | 25 | if(row == 0 || col == 0) continue; 26 | for(var j = 0;j < 3;j ++){ 27 | outData[i + j] = data[A + j] - data[G + j] + 127.5; 28 | } 29 | outData[i + 4] = data[i + 4]; 30 | } 31 | 32 | for(var i = 0,n = data.length;i < n;i ++){ 33 | data[i] = outData[i] || data[i]; 34 | } 35 | 36 | 37 | return imgData; 38 | } 39 | }; 40 | 41 | return M; 42 | 43 | }); 44 | 45 | })("psLib"); 46 | -------------------------------------------------------------------------------- /test/testView.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 73 | 74 | 75 | 76 | -------------------------------------------------------------------------------- /src/module/alteration/setHSI.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 调整RGB 饱和和度 4 | * H (-2*Math.PI , 2 * Math.PI) S (-100,100) I (-100,100) 5 | * 着色原理 勾选着色后,所有的像素不管之前是什么色相,都变成当前设置的色相, 6 | * 然后饱和度变成现在设置的饱和度,但保持明度为原来的基础上加上设置的明度 7 | * 8 | */ 9 | ;(function(Ps){ 10 | 11 | window[Ps].module("Alteration.setHSI",function(P){ 12 | 13 | var M = { 14 | process: function(imgData,arg){//调节亮度对比度 15 | arg[0] = arg[0] / 180 * Math.PI; 16 | arg[1] = arg[1] / 100 || 0; 17 | arg[2] = arg[2] / 100 * 255 || 0; 18 | arg[3] = arg[3] || false;//着色 19 | 20 | //调节通道 21 | var channel = arg[4]; 22 | if(!(/[RGBCMY]+/.test(channel))){ 23 | channel = "RGBCMY"; 24 | } 25 | 26 | var letters = channel.split(""); 27 | var indexOf = {}; 28 | 29 | for(var i = 0; i < letters.length; i ++){ 30 | indexOf[letters[i]] = 1; 31 | } 32 | 33 | P.lib.dorsyMath.applyInHSI(imgData,function(i, color){ 34 | if(! indexOf[color]) return; 35 | 36 | if(arg[3]){ 37 | i.H = arg[0]; 38 | i.S = arg[1]; 39 | i.I += arg[2]; 40 | }else{ 41 | i.H += arg[0]; 42 | i.S += arg[1]; 43 | i.I += arg[2]; 44 | } 45 | 46 | }); 47 | 48 | return imgData; 49 | } 50 | }; 51 | 52 | return M; 53 | 54 | }); 55 | 56 | })("psLib"); 57 | -------------------------------------------------------------------------------- /src/module/alteration/curve.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 曲线 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Alteration.curve", function(P){ 9 | 10 | var M = { 11 | process: function(imgData, arg){ 12 | /* 13 | * arg arg[0] = [3,3] ,arg[1] = [2,2] 14 | * */ 15 | 16 | //获得插值函数 17 | var f = P.lib.dorsyMath.lagrange(arg[0], arg[1]); 18 | var data = imgData.data; 19 | var width = imgData.width; 20 | var height = imgData.height; 21 | 22 | //调节通道 23 | var channel = arg[2]; 24 | if(!(/[RGB]+/.test(channel))){ 25 | channel = "RGB"; 26 | } 27 | 28 | var channelString = channel.replace("R","0").replace("G","1").replace("B","2"); 29 | 30 | var indexOfArr = [ 31 | channelString.indexOf("0") > -1, 32 | channelString.indexOf("1") > -1, 33 | channelString.indexOf("2") > -1 34 | ]; 35 | 36 | //区块 37 | for(var x = 0; x < width; x ++){ 38 | 39 | for(var y = 0; y < height; y ++){ 40 | 41 | var realI = y * width + x; 42 | 43 | for(var j = 0; j < 3; j ++){ 44 | if(! indexOfArr[j]) continue; 45 | data[realI * 4 + j] = f(data[realI * 4 + j]); 46 | } 47 | 48 | } 49 | 50 | } 51 | 52 | return imgData; 53 | } 54 | }; 55 | 56 | return M; 57 | 58 | }); 59 | 60 | })("psLib"); 61 | -------------------------------------------------------------------------------- /nsrc/alloyimage.define.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlloyImage Define Module 3 | * Just Like requireJS, but for js library 4 | * @author dorsywang 5 | */ 6 | ;(function(){ 7 | //define modules 8 | var mainPort = 'AlloyImage'; 9 | var __definePools__ = {}; 10 | 11 | //checking if modules ready; 12 | var checkReady = function(name){ 13 | if(__definePools__[name]){ 14 | var modules = __definePools__[name].modules; 15 | 16 | var readyModule = []; 17 | modules.map(function(item, index){ 18 | var itemObject = checkReady(item); 19 | if(itemObject){ 20 | readyModule.push(itemObject); 21 | }else{ 22 | } 23 | }); 24 | 25 | if(readyModule.length == modules.length){ 26 | return __definePools__[name].func.apply(null, readyModule); 27 | } 28 | }else{ 29 | } 30 | 31 | }; 32 | 33 | //AI define method, just like common define method; 34 | var AIDefine = function(name, modules, func){ 35 | __definePools__[name] = { 36 | func: func, 37 | modules: modules 38 | }; 39 | 40 | checkReady(mainPort); 41 | }; 42 | 43 | //Global Object: AlloyImage Or $AI; 44 | window.$AI = window.AlloyImage = AlloyImage = $AI = function(){}; 45 | 46 | //AI export method, just like common export method; 47 | var AIExport = { 48 | put: function(name, obj){ 49 | if(name === ""){ 50 | for(var i in obj){ 51 | $AI[i] = obj[i]; 52 | } 53 | }else{ 54 | $AI[name] = obj; 55 | } 56 | }, 57 | 58 | external: function(name, obj){ 59 | window[name] = obj; 60 | } 61 | }; 62 | 63 | AIExport.external('AIExport', AIExport); 64 | AIExport.external('AIDefine', AIDefine); 65 | 66 | })(); 67 | -------------------------------------------------------------------------------- /src/module/filter/mosaic.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 马赛克 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.mosaic",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){//调节亮度对比度 12 | var R = parseInt(arg[0]) || 3; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | var xLength = R * 2 + 1; 17 | 18 | for(var x = 0,n = parseInt(width / xLength);x < n;x ++){ 19 | 20 | for(var y = 0,m = parseInt(height / xLength);y < m;y ++){ 21 | 22 | var average = [],sum = [0,0,0]; 23 | for(var i = 0;i < xLength;i ++){ 24 | 25 | for(var j = 0;j < xLength;j ++){ 26 | var realI = (y * xLength + i) * width + x * xLength + j; 27 | sum[0] += data[realI * 4]; 28 | sum[1] += data[realI * 4 + 1]; 29 | sum[2] += data[realI * 4 + 2]; 30 | } 31 | } 32 | average[0] = sum[0] / (xLength * xLength); 33 | average[1] = sum[1] / (xLength * xLength); 34 | average[2] = sum[2] / (xLength * xLength); 35 | 36 | for(var i = 0;i < xLength;i ++){ 37 | 38 | for(var j = 0;j < xLength;j ++){ 39 | var realI = (y * xLength + i) * width + x * xLength + j; 40 | data[realI * 4] = average[0]; 41 | data[realI * 4 + 1] = average[1]; 42 | data[realI * 4 + 2] = average[2]; 43 | 44 | } 45 | } 46 | 47 | } 48 | 49 | } 50 | 51 | 52 | return imgData; 53 | } 54 | }; 55 | 56 | return M; 57 | 58 | }); 59 | 60 | })("psLib"); 61 | -------------------------------------------------------------------------------- /nsrc/alloyimage.fix.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlloyImage fix module 3 | * @author dorsywang From Tencent AlloyTeam 4 | */ 5 | 6 | AIDefine('fix', [], function(){ 7 | function detectVerticalSquash(img) { 8 | var iw = img.naturalWidth, ih = img.naturalHeight; 9 | var canvas = document.createElement('canvas'); 10 | canvas.width = 1; 11 | canvas.height = ih; 12 | var ctx = canvas.getContext('2d'); 13 | ctx.drawImage(img, 0, 0); 14 | var data = ctx.getImageData(0, 0, 1, ih).data; 15 | // search image edge pixel position in case it is squashed vertically. 16 | var sy = 0; 17 | var ey = ih; 18 | var py = ih; 19 | while (py > sy) { 20 | var alpha = data[(py - 1) * 4 + 3]; 21 | if (alpha === 0) { 22 | ey = py; 23 | } else { 24 | sy = py; 25 | } 26 | py = (ey + sy) >> 1; 27 | } 28 | var ratio = (py / ih); 29 | return (ratio===0)?1:ratio; 30 | } 31 | 32 | /** 33 | * A replacement for context.drawImage 34 | * (args are for source and destination). 35 | */ 36 | function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { 37 | var vertSquashRatio = detectVerticalSquash(img); 38 | // Works only if whole image is displayed: 39 | // ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); 40 | // The following works correct also when only a part of the image is displayed: 41 | ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio, 42 | sw * vertSquashRatio, sh * vertSquashRatio, 43 | dx, dy, dw, dh ); 44 | } 45 | 46 | function drawImageIOS(ctx, img, dw, dh){ 47 | var sx = 0, 48 | sy = 0, 49 | sw = img.width, 50 | sh = img.height, 51 | dx = 0, 52 | dy = 0; 53 | drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh); 54 | } 55 | 56 | 57 | var Fix = { 58 | drawImageIOS: drawImageIOS, 59 | drawImageIOSFix: drawImageIOSFix 60 | }; 61 | 62 | return Fix; 63 | }); 64 | -------------------------------------------------------------------------------- /src/module/fix.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @description: fix bugs 3 | * 4 | */ 5 | ;(function(Ps){ 6 | 7 | window[Ps].module("Fix",function(P){ 8 | function detectVerticalSquash(img) { 9 | var iw = img.naturalWidth, ih = img.naturalHeight; 10 | var canvas = document.createElement('canvas'); 11 | canvas.width = 1; 12 | canvas.height = ih; 13 | var ctx = canvas.getContext('2d'); 14 | ctx.drawImage(img, 0, 0); 15 | var data = ctx.getImageData(0, 0, 1, ih).data; 16 | // search image edge pixel position in case it is squashed vertically. 17 | var sy = 0; 18 | var ey = ih; 19 | var py = ih; 20 | while (py > sy) { 21 | var alpha = data[(py - 1) * 4 + 3]; 22 | if (alpha === 0) { 23 | ey = py; 24 | } else { 25 | sy = py; 26 | } 27 | py = (ey + sy) >> 1; 28 | } 29 | var ratio = (py / ih); 30 | return (ratio===0)?1:ratio; 31 | } 32 | 33 | /** 34 | * A replacement for context.drawImage 35 | * (args are for source and destination). 36 | */ 37 | function drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh) { 38 | var vertSquashRatio = detectVerticalSquash(img); 39 | // Works only if whole image is displayed: 40 | // ctx.drawImage(img, sx, sy, sw, sh, dx, dy, dw, dh / vertSquashRatio); 41 | // The following works correct also when only a part of the image is displayed: 42 | ctx.drawImage(img, sx * vertSquashRatio, sy * vertSquashRatio, 43 | sw * vertSquashRatio, sh * vertSquashRatio, 44 | dx, dy, dw, dh ); 45 | } 46 | 47 | function drawImageIOS(ctx, img, dw, dh){ 48 | var sx = 0, 49 | sy = 0, 50 | sw = img.width, 51 | sh = img.height, 52 | dx = 0, 53 | dy = 0; 54 | drawImageIOSFix(ctx, img, sx, sy, sw, sh, dx, dy, dw, dh); 55 | } 56 | 57 | 58 | var M = { 59 | drawImageIOS: drawImageIOS, 60 | drawImageIOSFix: drawImageIOSFix 61 | }; 62 | 63 | return M; 64 | 65 | }); 66 | 67 | })("psLib"); 68 | 69 | -------------------------------------------------------------------------------- /src/module/applyMatrix.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 查找边缘 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("applyMatrix",function(P){ 9 | 10 | var M = { 11 | process: function(imgData, arg){ 12 | var lamta = arg || 0.6; 13 | var data = imgData.data; 14 | var width = imgData.width; 15 | var height = imgData.height; 16 | var template = new P.lib.dorsyMath.Matrix([ 17 | -2,-4,-4,-4,-2, 18 | -4,0,8,0,-4, 19 | -4,8,24,8,-4, 20 | -4,0,8,0,-4, 21 | -2,-4,-4,-4,-2 22 | ],25,1); 23 | var tempData = []; 24 | 25 | for(var i = 0, n = data.length; i < n; i += 4){ 26 | var ii = i / 4; 27 | var row = parseInt(ii / width); 28 | var col = ii % width; 29 | if(row == 0 || col == 0) continue; 30 | 31 | var pixelArr = [[],[],[]]; 32 | 33 | for(var k = -2; k < 3; k ++){ 34 | var currRow = row + k; 35 | 36 | for(var kk = -2; kk < 3; kk ++){ 37 | 38 | var currCol = col + kk; 39 | var currI = (currRow * width + currCol) * 4; 40 | 41 | for(var j = 0; j < 3; j ++){ 42 | var tempI = currI + j; 43 | pixelArr[j].push(data[tempI]); 44 | } 45 | 46 | } 47 | 48 | } 49 | 50 | var pixelMatrix = new P.lib.dorsyMath.Matrix(pixelArr, 3, matrixSize); 51 | var resultMatrix = pixelMatrix.mutiply(template); 52 | 53 | for(var j = 0; j < 3; j ++){ 54 | tempData[i + j] = resultMatrix.data[j]; 55 | } 56 | 57 | tempData[i + 4] = data[i + 4]; 58 | } 59 | 60 | for(var i = 0, n = data.length; i < n; i ++){ 61 | data[i] = tempData[i] || data[i]; 62 | } 63 | 64 | return imgData; 65 | } 66 | }; 67 | 68 | return M; 69 | 70 | }); 71 | 72 | })("psLib"); 73 | -------------------------------------------------------------------------------- /src/module/filter/darkCorner.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 暗角 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.darkCorner", function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){ 12 | //暗角级别 分1-10级吧 13 | var R = parseInt(arg[0]) || 3; 14 | 15 | //暗角的形状 16 | var type = arg[2] || "round"; 17 | 18 | //暗角最终的级别 0 - 255 19 | var lastLevel = arg[1] || 30; 20 | 21 | var data = imgData.data; 22 | var width = imgData.width; 23 | var height = imgData.height; 24 | var xLength = R * 2 + 1; 25 | 26 | //计算中心点 27 | var middleX = width * 2 / 3; 28 | var middleY = height * 1/ 2; 29 | 30 | //计算距中心点最长距离 31 | var maxDistance = P.lib.dorsyMath.distance([middleX ,middleY]); 32 | //开始产生暗角的距离 33 | var startDistance = maxDistance * (1 - R / 10); 34 | 35 | var f = function(x, p0, p1, p2, p3){ 36 | 37 | //基于三次贝塞尔曲线 38 | return p0 * Math.pow((1 - x), 3) + 3 * p1 * x * Math.pow((1 - x), 2) + 3 * p2 * x * x * (1 - x) + p3 * Math.pow(x, 3); 39 | } 40 | 41 | //计算当前点应增加的暗度 42 | function calDark(x, y, p){ 43 | //计算距中心点距离 44 | var distance = P.lib.dorsyMath.distance([x, y], [middleX, middleY]); 45 | var currBilv = (distance - startDistance) / (maxDistance - startDistance); 46 | if(currBilv < 0) currBilv = 0; 47 | 48 | //应该增加暗度 49 | return f(currBilv, 0, 0.02, 0.3, 1) * p * lastLevel / 255; 50 | } 51 | 52 | //区块 53 | for(var x = 0; x < width; x ++){ 54 | 55 | for(var y = 0; y < height; y ++){ 56 | 57 | var realI = y * width + x; 58 | for(var j = 0;j < 3;j ++){ 59 | var dDarkness = calDark(x, y, data[realI * 4 + j]); 60 | data[realI * 4 + j] -= dDarkness; 61 | } 62 | 63 | } 64 | 65 | } 66 | 67 | 68 | return imgData; 69 | } 70 | }; 71 | 72 | return M; 73 | 74 | }); 75 | 76 | })("psLib"); 77 | -------------------------------------------------------------------------------- /src/module/filter/dotted.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 马赛克 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.dotted",function(P){ 9 | 10 | var M = { 11 | process: function(imgData,arg){//调节亮度对比度 12 | //矩形半径 13 | var R = parseInt(arg[0]) || 1; 14 | 15 | //内小圆半径 16 | var r = parseInt(arg[1]) || 1; 17 | 18 | var data = imgData.data; 19 | var width = imgData.width; 20 | var height = imgData.height; 21 | var xLength = R * 2 + 1; 22 | 23 | //构造距离模板 24 | var disTmlMatrix = [ 25 | ]; 26 | 27 | var r2 = r * r; 28 | for(var x = -R; x < R; x ++){ 29 | 30 | for(var y = -R; y < R; y ++){ 31 | if((x * x + y * y) > r2){ 32 | disTmlMatrix.push([x, y]); 33 | } 34 | } 35 | 36 | } 37 | 38 | var xyToIFun = P.lib.dorsyMath.xyToIFun(width); 39 | 40 | //将大于距离外面的透明度置为0 41 | for(var x = 0, n = parseInt(width / xLength); x < n; x ++){ 42 | 43 | for(var y = 0, m = parseInt(height / xLength); y < m;y ++){ 44 | var middleX = parseInt((x + 0.5) * xLength); 45 | var middleY = parseInt((y + 0.5) * xLength); 46 | 47 | for(var i = 0; i < disTmlMatrix.length; i ++){ 48 | var dotX = middleX + disTmlMatrix[i][0]; 49 | var dotY = middleY + disTmlMatrix[i][1]; 50 | 51 | //data[(dotY * width + dotX) * 4 + 3] = 0; 52 | data[xyToIFun(dotX, dotY, 3)] = 225; 53 | data[xyToIFun(dotX, dotY, 2)] = 225; 54 | data[xyToIFun(dotX, dotY, 0)] = 225; 55 | data[xyToIFun(dotX, dotY, 1)] = 225; 56 | } 57 | } 58 | 59 | } 60 | 61 | /* 62 | for(var x = 0; x < width; x ++){ 63 | for(var y = 0; y < height; y ++){ 64 | data[(y * width + x) * 4 + 3] = 0; 65 | } 66 | } 67 | */ 68 | 69 | 70 | return imgData; 71 | } 72 | }; 73 | 74 | return M; 75 | 76 | }); 77 | 78 | })("psLib"); 79 | -------------------------------------------------------------------------------- /nsrc/alloyimage.config.js: -------------------------------------------------------------------------------- 1 | AIDefine('config', [], function(){ 2 | //记录映射关系 3 | var Reflection = { 4 | //调整 5 | Alteration: { 6 | "亮度": "brightness", 7 | "色相/饱和度调节": "setHSI", 8 | "曲线" : "curve", 9 | "gamma调节" : "gamma", 10 | "可选颜色": "selectiveColor" 11 | }, 12 | 13 | //滤镜 14 | Filter: { 15 | "灰度处理": "toGray", 16 | "反色": "toReverse", 17 | "灰度阈值": "toThresh", 18 | "高斯模糊": "gaussBlur", 19 | "浮雕效果": "embossment", 20 | "查找边缘": "borderline", 21 | "马赛克": "mosaic", 22 | "油画": "oilPainting", 23 | "腐蚀": "corrode", 24 | "锐化" : "sharp", 25 | "添加杂色" : "noise", 26 | "暗角" : "darkCorner", 27 | "喷点" : "dotted", 28 | "降噪" : "denoise", 29 | "棕褐色" : "sepia", 30 | "色调分离" : "posterize" 31 | }, 32 | 33 | ComEffect: { 34 | "美肤" : "softenFace", 35 | "素描" : "sketch", 36 | "自然增强" : "softEnhancement", 37 | "紫调" : "purpleStyle", 38 | "柔焦" : "soften", 39 | "复古" : "vintage", 40 | "黑白" : "gray", 41 | "仿lomo" : "lomo", 42 | "亮白增强" : "strongEnhancement", 43 | "灰白" : "strongGray", 44 | "灰色" : "lightGray", 45 | "暖秋" : "warmAutumn", 46 | "木雕" : "carveStyle", 47 | "粗糙" : "rough" 48 | } 49 | }; 50 | 51 | //转换映射关系 便于查找 52 | var revertReflection = function(){ 53 | var result = {}; 54 | 55 | for(var i in Reflection){ 56 | //comEffect 组合效果不遍历 57 | if(i == "ComEffect") continue; 58 | 59 | for(var j in Reflection[i]){ 60 | result[j] = i; 61 | result[Reflection[i][j]] = i; 62 | } 63 | } 64 | 65 | return result; 66 | }(); 67 | 68 | var Config = { 69 | 70 | getModuleName: function(method){ 71 | var spaceName; 72 | 73 | if(spaceName = revertReflection[method]){ 74 | var actName = Reflection[spaceName][method] || method; 75 | return { 76 | spaceName: spaceName, 77 | actName: actName 78 | }; 79 | 80 | }else{ 81 | P.destroySelf("AI_ERROR:调用AI不存在的方法" + method); 82 | } 83 | }, 84 | 85 | //组合效果 86 | getEasyFun: function(effect){ 87 | return { 88 | spaceName: "ComEffect", 89 | actName: Reflection.ComEffect[effect] || effect 90 | }; 91 | }, 92 | 93 | getConfig: function(){ 94 | return Reflection; 95 | } 96 | }; 97 | 98 | return Config; 99 | 100 | }); 101 | -------------------------------------------------------------------------------- /src/module/config.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: Main config 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("config",function(P){ 9 | 10 | //记录映射关系 11 | var Reflection = { 12 | //调整 13 | Alteration: { 14 | "亮度": "brightness", 15 | "色相/饱和度调节": "setHSI", 16 | "曲线" : "curve", 17 | "gamma调节" : "gamma", 18 | "可选颜色": "selectiveColor" 19 | }, 20 | 21 | //滤镜 22 | Filter: { 23 | "灰度处理": "toGray", 24 | "反色": "toReverse", 25 | "灰度阈值": "toThresh", 26 | "高斯模糊": "gaussBlur", 27 | "浮雕效果": "embossment", 28 | "查找边缘": "borderline", 29 | "马赛克": "mosaic", 30 | "油画": "oilPainting", 31 | "腐蚀": "corrode", 32 | "锐化" : "sharp", 33 | "添加杂色" : "noise", 34 | "暗角" : "darkCorner", 35 | "喷点" : "dotted", 36 | "降噪" : "denoise", 37 | "棕褐色" : "sepia", 38 | "色调分离" : "posterize" 39 | }, 40 | 41 | ComEffect: { 42 | "美肤" : "softenFace", 43 | "素描" : "sketch", 44 | "自然增强" : "softEnhancement", 45 | "紫调" : "purpleStyle", 46 | "柔焦" : "soften", 47 | "复古" : "vintage", 48 | "黑白" : "gray", 49 | "仿lomo" : "lomo", 50 | "亮白增强" : "strongEnhancement", 51 | "灰白" : "strongGray", 52 | "灰色" : "lightGray", 53 | "暖秋" : "warmAutumn", 54 | "木雕" : "carveStyle", 55 | "粗糙" : "rough" 56 | } 57 | }; 58 | 59 | //转换映射关系 便于查找 60 | var revertReflection = function(){ 61 | var result = {}; 62 | 63 | for(var i in Reflection){ 64 | //comEffect 组合效果不遍历 65 | if(i == "ComEffect") continue; 66 | 67 | for(var j in Reflection[i]){ 68 | result[j] = i; 69 | result[Reflection[i][j]] = i; 70 | } 71 | } 72 | 73 | return result; 74 | }(); 75 | 76 | var Config = { 77 | 78 | getModuleName: function(method){ 79 | var spaceName; 80 | 81 | if(spaceName = revertReflection[method]){ 82 | var actName = Reflection[spaceName][method] || method; 83 | return { 84 | spaceName: spaceName, 85 | actName: actName 86 | }; 87 | 88 | }else{ 89 | throw new Error("AI_ERROR:调用AI不存在的方法" + method); 90 | } 91 | }, 92 | 93 | //组合效果 94 | getEasyFun: function(effect){ 95 | return { 96 | spaceName: "ComEffect", 97 | actName: Reflection.ComEffect[effect] || effect 98 | }; 99 | }, 100 | 101 | getConfig: function(){ 102 | return Reflection; 103 | } 104 | }; 105 | 106 | return Config; 107 | 108 | }); 109 | 110 | })("psLib"); 111 | -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 137 | 138 | 139 | -------------------------------------------------------------------------------- /nsrc/alloyimage.process.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlloyImage process module 3 | * The main Process module For AlloyImage, It's private; 4 | * @author dorsywang From Tencent AlloyTeam 5 | */ 6 | 7 | AIDefine('process', ['config', 'layer'], function(Config, Layer){ 8 | var Process = { 9 | 10 | //模块池 11 | lib: [], 12 | 13 | //外部定义的ps效果 14 | definedPs: {}, 15 | 16 | //初始化准备 17 | init: function(){ 18 | this.require("config"); 19 | }, 20 | 21 | //模块注册方法 22 | module: function(name, func){ 23 | var moduleArr = [name]; 24 | if(/\./g.test(name)){ 25 | moduleArr = name.split("."); 26 | } 27 | 28 | var count = -1, _this = this; 29 | function addModule(obj){ 30 | count ++; 31 | 32 | var attr = moduleArr[count]; 33 | 34 | //递归出口 35 | if(count == moduleArr.length - 1){ 36 | obj[attr] = func.call(null, _this); 37 | 38 | return; 39 | } 40 | 41 | obj[attr] ? addModule(obj[attr]) : addModule(obj[attr] = {}); 42 | } 43 | 44 | addModule(this.lib); 45 | 46 | }, 47 | 48 | //加载文件 49 | require: function(name){ 50 | var _this = this; 51 | var scriptLoader = document.createElement("script"); 52 | 53 | document.body.appendChild(scriptLoader); 54 | scriptLoader.src = "./js/module/" + name + ".js"; 55 | scriptLoader.onload = scriptLoader.onerror = function(e){ 56 | _this.handlerror(e); 57 | } 58 | }, 59 | 60 | //错误处理部分 61 | handlerror: function(e){ 62 | //this.destroySelf("程序因未知原因中断"); 63 | }, 64 | 65 | //程序被迫自杀,杀前请留下遗嘱 66 | destroySelf: function(msg){ 67 | delete window[Ps]; 68 | var e = new Error(msg); 69 | throw(e); 70 | }, 71 | 72 | //映射器,将中文方法或...映射为实际方法 73 | reflect: function(method, imgData, args){ 74 | 75 | //得到实际的模块名称 76 | var moduleName = Config.getModuleName(method); 77 | 78 | var spaceName = moduleName.spaceName; 79 | var actName = moduleName.actName; 80 | 81 | switch(spaceName){ 82 | case "Filter": 83 | return Filter[actName].process(imgData, args); 84 | 85 | case "Alteration": 86 | 87 | return Alteration[actName].process(imgData, args); 88 | //break; 89 | 90 | case "ComEffect": 91 | return ComEffect[actName].process(imgData, args); 92 | //break; 93 | 94 | default: 95 | //逻辑几乎不会到这里 出于好的习惯,加上default 96 | this.destroySelf("AI_ERROR: "); 97 | } 98 | }, 99 | 100 | //组合效果映射器 101 | reflectEasy: function(effect){ 102 | var fun = Config.getEasyFun(effect).actName; 103 | return this.definedPs[effect] || ComEffect.getFun(fun); 104 | }, 105 | 106 | //合并一个图层到对象 107 | add: function(lowerData, upperData, method, alpha, dx, dy, isFast, channel){ 108 | return Layer.add(lowerData, upperData, method, alpha, dx, dy, isFast, channel); 109 | }, 110 | 111 | //用worker进行异步处理 112 | worker: function(func, callback){ 113 | 114 | }, 115 | 116 | //对图像进行掩模算子变换 117 | applyMatrix: function(imgData, matrixArr){ 118 | }, 119 | 120 | //args[0]代表处理方法,args[1...]代表参数 121 | tools: function(imgData, args){ 122 | var actMethod = Array.prototype.shift.call(args); 123 | 124 | if(this.lib.Tools[actMethod]){ 125 | return this.lib.Tools[actMethod].process(imgData, args); 126 | }else{ 127 | throw new Error("AI_ERROR: 不存在的工具方法_" + actMethod); 128 | } 129 | }, 130 | 131 | definePs: function(name, func){ 132 | this.definedPs[name] = func; 133 | } 134 | }; 135 | 136 | return Process; 137 | }); 138 | -------------------------------------------------------------------------------- /src/module/easy.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 腐蚀 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("easy",function(P){ 9 | 10 | var M = { 11 | getFun: function(fun){ 12 | var Effects = { 13 | softenFace: function(){//美肤 14 | var _this = this.clone(); 15 | return _this.add( 16 | this.act("高斯模糊",10),"滤色" 17 | ).act("亮度",-10,5); 18 | }, 19 | sketch: function(){//素描 20 | var _this = this.clone(); 21 | return this.add( 22 | _this.act("反色").act("高斯模糊",8), "颜色减淡" 23 | ).act("toGray").act("锐化",1); 24 | }, 25 | softEnhancement: function(){//自然增强 26 | return this.act("曲线",[0,190,255],[0,229,255]); 27 | }, 28 | purpleStyle: function(){ 29 | var _this = this.clone(); 30 | return this.add( 31 | _this.act("高斯模糊",3), "正片叠底" ,"RG" 32 | ); 33 | 34 | }, 35 | soften: function(){ 36 | var _this = this.clone(); 37 | return this.add( 38 | _this.act("高斯模糊",6), "变暗" 39 | ); 40 | }, 41 | vintage: function(){//复古 42 | var _this = this.clone(); 43 | return this.act("灰度处理").add( 44 | window[Ps](this.canvas.width,this.canvas.height,"#808080").act("添加杂色").act("高斯模糊",4).act("色相/饱和度调节",32,19,0,true),"叠加" 45 | ); 46 | }, 47 | gray: function(){//黑白 48 | return this.act("灰度处理"); 49 | }, 50 | lomo: function(){//仿lomo 51 | var m = this.clone().add( 52 | this.clone() , "滤色" 53 | ).add( 54 | this.clone() , "柔光" 55 | ); 56 | 57 | return m.add( 58 | this.clone().act("反色") , "正常","20%","B" 59 | ).act("暗角", 6, 200); 60 | 61 | }, 62 | strongEnhancement: function(){ 63 | return this.clone().add( 64 | this.clone().act("曲线",[0,50,255],[0,234,255]), "柔光" 65 | ); 66 | }, 67 | strongGray: function(){//高对比 灰白 68 | return this.act("灰度处理").act("曲线",[0,61,69,212,255],[0,111,176,237,255]); 69 | }, 70 | lightGray: function(){ 71 | return this.act("灰度处理").act("曲线",[0,60,142,194,255],[0,194,240,247,255]) 72 | }, 73 | warmAutumn: function(){ 74 | var m = this.clone().act("色相/饱和度调节",36,47,8,true).act("暗角", 6, 150); 75 | return this.add( 76 | m, "叠加" 77 | ); 78 | }, 79 | 80 | //木雕的效果 81 | carveStyle: function(){ 82 | var layerClone = this.clone().act("马赛克").act("查找边缘").act("浮雕效果"); 83 | return this.add( 84 | layerClone, "线性光" 85 | ); 86 | }, 87 | 88 | //粗糙 89 | rough: function(){ 90 | return this.add( 91 | 92 | window[Ps](this.canvas.width, this.canvas.height, "#000").act("喷点").act("反色").act("浮雕效果") 93 | ,"叠加" 94 | ); 95 | } 96 | }; 97 | 98 | return Effects[fun]; 99 | } 100 | }; 101 | 102 | return M; 103 | 104 | }); 105 | 106 | })("psLib"); 107 | -------------------------------------------------------------------------------- /src/module/dorsyWorker.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: Main worker 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("dorsyWorker",function(P){ 9 | //等待时间 10 | var WAITING_SECONDS = 200; 11 | 12 | var M = function(aiObj){ 13 | //static private single 14 | var worker = new Worker(P.path);// + "?" + (+ new Date())); 15 | if(! worker){ 16 | throw new Error("使用worker时,alloyimage文件目录指定出错"); 17 | } 18 | 19 | var workerObj = { 20 | //等待处理的队列 21 | queue: [], 22 | //开始进入多线程 23 | startWorker: function(){ 24 | //console.log("startWorker"); 25 | this.shiftAction(); 26 | }, 27 | 28 | //从队列中取出一个动作来处理 29 | shiftAction: function(){ 30 | var action = this.queue.shift(), _this = this; 31 | 32 | //如果没有了,等待100ms再次检查, 如果还没有,表明队列中无新增处理动作, readyOK 33 | if(! action){ 34 | setTimeout(function(){ 35 | action = _this.queue.shift(); 36 | 37 | if(! action){ 38 | aiObj.notify("readyStateOK"); 39 | //console.log("readyStateOK"); 40 | } 41 | 42 | }, WAITING_SECONDS); 43 | 44 | return; 45 | } 46 | 47 | //调用方法 48 | var actionMethod = action[0]; 49 | 50 | //此处理为动作 51 | if(actionMethod == "act"){ 52 | 53 | //向worker发消息 54 | worker.postMessage(["act", action[1], aiObj.imgData, action[2]]); 55 | 56 | //为添加要检查添加的图层是否处理完成 57 | }else if(actionMethod == "add"){ 58 | //console.log("add"); 59 | 60 | 61 | function checkReadyState(){ 62 | 63 | //完成 64 | if(action[1].readyState){ 65 | 66 | //构造参数 67 | var params = [ 68 | aiObj.imgData, 69 | action[1].imgData 70 | ].concat( 71 | action.slice(2) 72 | ); 73 | 74 | worker.postMessage(["add", params]); 75 | 76 | //如果没有完成则不断检查是否完成,期间可以做其他的动作,但处理暂时中止 77 | }else{ 78 | setTimeout(function(){ 79 | checkReadyState(); 80 | }, WAITING_SECONDS); 81 | } 82 | } 83 | 84 | checkReadyState(); 85 | }else if(actionMethod == "show"){ 86 | aiObj.show(action[1], action[2], 1); 87 | this.shiftAction(); 88 | 89 | //遇到回调出现 90 | }else if(actionMethod == "complete"){ 91 | //console.log("complete trigger"); 92 | action[1] && action[1](); 93 | this.shiftAction(); 94 | 95 | //如果是复制图层 96 | }else if(actionMethod == "clone"){ 97 | aiObj.clone(1); 98 | this.shiftAction(); 99 | }else if(actionMethod == "save"){ 100 | aiObj.save(0, 1); 101 | this.shiftAction(); 102 | }else if(actionMethod == "replace"){ 103 | aiObj.replace(action[1], 1); 104 | this.shiftAction(); 105 | } 106 | }, 107 | 108 | //worker回调监听 109 | callback: function(data){ 110 | //console.log("callback"); 111 | aiObj.imgData = data; 112 | this.shiftAction(); 113 | } 114 | }; 115 | 116 | //收到消息后再从队列中检查然后进行处理 117 | worker.onmessage = function(e){ 118 | //console.log("onmessage"); 119 | workerObj.callback(e.data); 120 | }; 121 | 122 | return workerObj; 123 | }; 124 | 125 | return M; 126 | 127 | }); 128 | 129 | })("psLib"); 130 | 131 | -------------------------------------------------------------------------------- /src/module/filter/gaussBlur.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: az@alloyTeam Bin Wang 3 | * @description: 高斯模糊 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Filter.gaussBlur",function(P){ 9 | 10 | var M = { 11 | 12 | /** 13 | * 高斯模糊 14 | * @param {Array} pixes pix array 15 | * @param {Number} width 图片的宽度 16 | * @param {Number} height 图片的高度 17 | * @param {Number} radius 取样区域半径, 正数, 可选, 默认为 3.0 18 | * @param {Number} sigma 标准方差, 可选, 默认取值为 radius / 3 19 | * @return {Array} 20 | */ 21 | process: function(imgData, args) { 22 | var pixes = imgData.data; 23 | var width = imgData.width; 24 | var height = imgData.height; 25 | var gaussMatrix = [], 26 | gaussSum = 0, 27 | x, y, 28 | r, g, b, a, 29 | i, j, k, len; 30 | 31 | var radius = args[0]; 32 | var sigma = args[1]; 33 | 34 | 35 | radius = Math.floor(radius) || 3; 36 | sigma = sigma || radius / 3; 37 | 38 | a = 1 / (Math.sqrt(2 * Math.PI) * sigma); 39 | b = -1 / (2 * sigma * sigma); 40 | //生成高斯矩阵 41 | for (i = 0, x = -radius; x <= radius; x++, i++){ 42 | g = a * Math.exp(b * x * x); 43 | gaussMatrix[i] = g; 44 | gaussSum += g; 45 | 46 | } 47 | //归一化, 保证高斯矩阵的值在[0,1]之间 48 | for (i = 0, len = gaussMatrix.length; i < len; i++) { 49 | gaussMatrix[i] /= gaussSum; 50 | } 51 | //x 方向一维高斯运算 52 | for (y = 0; y < height; y++) { 53 | for (x = 0; x < width; x++) { 54 | r = g = b = a = 0; 55 | gaussSum = 0; 56 | for(j = -radius; j <= radius; j++){ 57 | k = x + j; 58 | if(k >= 0 && k < width){//确保 k 没超出 x 的范围 59 | //r,g,b,a 四个一组 60 | i = (y * width + k) * 4; 61 | r += pixes[i] * gaussMatrix[j + radius]; 62 | g += pixes[i + 1] * gaussMatrix[j + radius]; 63 | b += pixes[i + 2] * gaussMatrix[j + radius]; 64 | // a += pixes[i + 3] * gaussMatrix[j]; 65 | gaussSum += gaussMatrix[j + radius]; 66 | } 67 | } 68 | i = (y * width + x) * 4; 69 | // 除以 gaussSum 是为了消除处于边缘的像素, 高斯运算不足的问题 70 | // console.log(gaussSum) 71 | pixes[i] = r / gaussSum; 72 | pixes[i + 1] = g / gaussSum; 73 | pixes[i + 2] = b / gaussSum; 74 | // pixes[i + 3] = a ; 75 | } 76 | } 77 | //y 方向一维高斯运算 78 | for (x = 0; x < width; x++) { 79 | for (y = 0; y < height; y++) { 80 | r = g = b = a = 0; 81 | gaussSum = 0; 82 | for(j = -radius; j <= radius; j++){ 83 | k = y + j; 84 | if(k >= 0 && k < height){//确保 k 没超出 y 的范围 85 | i = (k * width + x) * 4; 86 | r += pixes[i] * gaussMatrix[j + radius]; 87 | g += pixes[i + 1] * gaussMatrix[j + radius]; 88 | b += pixes[i + 2] * gaussMatrix[j + radius]; 89 | // a += pixes[i + 3] * gaussMatrix[j]; 90 | gaussSum += gaussMatrix[j + radius]; 91 | } 92 | } 93 | i = (y * width + x) * 4; 94 | pixes[i] = r / gaussSum; 95 | pixes[i + 1] = g / gaussSum; 96 | pixes[i + 2] = b / gaussSum; 97 | // pixes[i] = r ; 98 | // pixes[i + 1] = g ; 99 | // pixes[i + 2] = b ; 100 | // pixes[i + 3] = a ; 101 | } 102 | } 103 | //end 104 | imgData.data = pixes; 105 | return imgData; 106 | } 107 | }; 108 | 109 | return M; 110 | 111 | }); 112 | 113 | })("psLib"); 114 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [AlloyImage](http://alloyteam.github.com/AlloyPhoto/) - 基于HTML5技术的专业图像处理库 2 | =========================== 3 | 4 | ### 功能特性 5 | 6 | #### 强大功能 7 | 1. 基于多图层操作 -- 一个图层的处理不影响其他图层 8 | 2. 与PS对应的17种图层混合模式 -- 便于PS处理教程的无缝迁移 9 | 3. 多种基本滤镜处理效果 -- 基本滤镜不断丰富、可扩展 10 | 4. 基本的图像调节功能 -- 色相、饱和度、对比度、亮度、曲线等 11 | 12 | 13 | #### 便捷开发 14 | 1. 简单快捷的API -- 链式处理、API简洁易用、传参灵活 15 | 2. 多种组合效果封装 -- 一句代码轻松实现一种风格 16 | 3. 友好参数支持 -- 中、英文参数双向支持,降低专业词汇记忆门槛 17 | 4. 接口一致的单、多线程支持 -- 单、多线程切换无需更改一行代码,多线程保持快捷API特性 18 | 5. 可预见的错误友好提醒 -- 对一些可能出现错误的地方提醒,方便开发与调试 19 | 20 | 21 | #### 丰富扩展 22 | 1. 方便的添加功能扩展 -- 轻松添加滤镜插件 23 | 2. 为扩展提供数学封装 -- 封装了一些数学模块供扩展调用 24 | 25 | ### 建议使用场景 26 | 1.桌面软件客户端内嵌网页运行方式 27 | >>>打包webkit内核: 用户较大头像上传风格处理、用户相册风格处理(处理时间平均<1s) 28 | 29 | 2.Win8 Metro应用 30 | >>>用户上传头像,比较小的图片风格处理后上传(Win8下IE10支持多线程) 31 | 32 | 3.Mobile APP 33 | >>>Andriod平台、IOS平台小图风格web处理的需求,如phoneGap应用, 在线头像上传时的风格处理、mobile web端分享图片时风格处理等 34 | 35 | ### 如何构建源码? 36 | 37 | 首先使用git clone复制一份AlloyPhoto的代码到本地: 38 | ```sh 39 | git clone git://github.com/AlloyTeam/AlloyPhoto.git 40 | ``` 41 | 然后使用npm安装[modjs](https://github.com/modulejs/modjs): 42 | ```sh 43 | npm install -g modjs 44 | ``` 45 | 安装成功后: 46 | ```sh 47 | cd AlloyPhoto && mod dist 48 | ``` 49 | 构建成功后会在 `./js/combined`目录下生成`alloyimage.js`文件 50 | 51 | ### 变更历史 52 | #### AlloyImage 1.2开发版代码 获取 53 | > 在release目录下获取开发版 54 | 55 | #### AlloyImage 1.2 开发中 56 | 1. 更改代码架构,分离Filter 57 | 2. 添加工具方法支持:色系提取 58 | 3. 添加下载文件方法 59 | 4. 添加 棕褐色 滤镜 60 | 5. 添加 色调分离 滤镜 61 | 6. 添加 Gamma 调节 62 | 7. 更改代码,分离Alteration 63 | 8. 添加仿射变换(缩放、平移、旋转)、裁切 64 | 9. 增加可选颜色调节 65 | 10. 曲线命令支持通道调节 66 | 11. 优化IOS下性能,修复变形的bug 67 | 68 | 69 | ##### 新增API 1.2以上 70 | 71 | >###$AI 或 AlloyImage 72 | 初始化一个AlloyImage对象
73 | 增加新的参数适配 AIObj $AI(HTMLImageObj img[, Number width, Number height]);
74 | {img} 图片元素
75 | {width} 缩放的宽度 可选
76 | {height} 缩放的高度 可选
77 | 如果width 或height一个为null,则使用等比缩放,如果都没有,使用img宽度 78 | tips: 在IOS下请使用width参数来缩放相册中的图片,IOS下不使用缩放,图片太大可能无法绘制到Canvas上
79 | 80 | 示例 81 | ```javascript 82 | var ps = $AI(img, 600).save('jpg', 0.6); 83 | ``` 84 | 85 | >###save 86 | 将合成图片保存成base64格式字符串
87 | base64String save(String filetype [, Number comRatio]);

88 | {filetype} 图片格式类型,支持png,jpg,gif等
89 | {comRatio} 对于jpg格式的图片,图片压缩比率或者图片质量,0 - 1的小数

90 | 返回 base64的字符串 91 | 92 | 示例 93 | ```javascript 94 | var string = AlloyImage(img).save('jpg', 0.8); 95 | ``` 96 | >###saveFile 97 | 将合成图片下载到本地
98 | void saveFile(String fileName[, Number comRatio]);

99 | {fileName} 图片文件名,如果不带后缀,默认为png格式
100 | {comRatio} 对于jpg格式的图片,图片压缩比率或者图片质量,0 - 1的小数

101 | 返回 空 102 | 103 | 示例 104 | ```javascript 105 | img.onclick = function(){ 106 | AlloyImage(this).saveFile('处理后图像.jpg', 0.8); 107 | } 108 | ``` 109 | 110 | >###download 111 | 功能与使用同saveFile 112 | 113 |   114 | 115 | >###transform 116 | 进行仿射变换
117 | AIObj transform(Array Matrix);

118 | {Matrix} 变换矩阵 数组 [a1, a2, b1, b2, dx, dy]
119 | 如水平翻转 [-1, 0, 0, 1, 0, 0]
120 | 示例 121 | ```javascript 122 | //将图层垂直翻转 123 | AlloyImage(img).transform([1, 0, 0, -1, 0, 0]).show(); 124 | ``` 125 | 126 |   127 | >###scaleTo 128 | 将图层或合成图像缩放到指定宽高
129 | AIObj scaleTo(Number width, Nubmer height);

130 | {width} 宽度
131 | {height} 高度
132 | 如果不指定某一参数,则使用等比缩放 133 |

134 | 返回 AIObj 135 | 136 | 示例 137 | ```javascript 138 | //将图层缩放放到100px * 100px 139 | AlloyImage(img).scaleTo(100, 100).show(); 140 | 141 | //将图层等比缩放到高50px 142 | AlloyImage(img).scaleTo(null, 100).show(); 143 | ``` 144 | >###scale 145 | 将图层或合成图像缩放指定倍数
146 | AIObj scale(Number xRatio, Nubmer yRatio);

147 | {xRatio} 横向缩放倍数
148 | {yRatio} 纵向缩放倍数
149 | 如果不指定某一参数,则使用等比缩放 150 |

151 | 返回 AIObj 152 | 153 | 示例 154 | ```javascript 155 | //将图层缩放放2 * 2倍 156 | AlloyImage(img).scale(2, 2).show(); 157 | 158 | //将图层等比缩放3倍 159 | AlloyImage(img).scale(3).show(); 160 | ``` 161 | >###rotate 162 | 将图层或合成图像旋转一定的角度
163 | AIObj rotate(Numbe degree);

164 | {degree} 顺时旋转角度,以度为单位
165 |

166 | 返回 AIObj 167 | 168 | 示例 169 | ```javascript 170 | //将图层旋转30度 171 | AlloyImage(img).rotate(30).show(); 172 | 173 | ``` 174 | 175 | >###clip 176 | 将图层或合成图像裁剪
177 | AIObj rotate(Numbe x0, Number y0, Number width, Number height);

178 | {x0} 起始横坐标
179 | {y0} 起始纵坐标
180 | {width} 裁剪图像宽度
181 | {height} 裁剪图像高度
182 |

183 | 返回 AIObj 184 | 185 | 示例 186 | ```javascript 187 | //将图层从(30, 30)开始裁剪宽100px高100px的图像,并获取图像base64代码 188 | var imgString = AlloyImage(img).clip(30, 30, 100, 100).save('jpg', 0.8); 189 | 190 | ``` 191 | 192 | >###drawRect 193 | 画出合成像的直方图
194 | void drawRect(String seletor, String channel);

195 | {seletor} 直方图绘制的wrapper
196 | {channel} 要绘制的通道, 比如 'RG', 'GB', 默认为'RGB' 197 |

198 | 返回 空 199 | 200 | 示例 201 | ```javascript 202 | var imgString = AlloyImage(img).drawRect('#p'); 203 | 204 | ``` 205 | 206 | ## 预览、撤销、重做 207 | >###doView 208 | 保存view的中间结果,下次使用view将会根据上次doView之前的结果进行处理,与undoView结合,可进行撤销操作
209 | AIObj doView();
210 | 返回 AIObj
211 | 示例参照undoView方法 212 | 213 |   214 | 215 | >###undoView 216 | 撤销上次view的执行结果 217 | AIObj undoView(); 218 | 返回 AIObj 219 | 220 | 示例 221 | ```javascript 222 | var layer = $AI(img); 223 | layer.view("setHSI", 10, 0, 0).show(); 224 | 225 | // 再次调节 这次还是基于原图调节 226 | layer.view("setHSI", -10, 0, 0).show(); 227 | 228 | //调节好了 保存这次结果 229 | layer.doView(); 230 | 231 | // 基于上次的调节结果进行计算 232 | layer.view("brightness", 10, 0, 0).show(); 233 | 234 | // 不满意 撤销亮度调节操作 235 | layer.undoView().show(); 236 | 237 | // 回到最原始的图像 238 | layer.undoView().show(); 239 | 240 | ``` 241 | 242 | 243 | 244 | 245 | 246 | #### AlloyImage 1.1 247 | 1. 优化代码,组合效果处理性能提升80% 248 | 2. 添加木雕组合效果 249 | 250 | #### AlloyImage 1.0 251 | 252 | ### 目录结构 253 | >--build 构建目录 一些项目的构建工具 254 | 255 | >--combined 中间构建合成的项目代码,用于测试和发布 256 | 257 | >--demo demo文件 258 | 259 | >--doc 目录文档 260 | 261 | >--release 已发布的文件版本 262 | 263 | >--res 一些测试用的静态资源 264 | 265 | >--src 项目JS源码 266 | 267 | >> alloyimage.base.js core文件 base文件 268 | 269 | >> --module 模块文件 270 | 271 | >> --alteration 调节模块 272 | 273 | >> --filter 滤镜插件 274 | >--test 测试文件 275 | 276 | ### 这些产品使用了AlloyImage 277 | 278 | [AlloyDesigner](http://alloyteam.github.io/AlloyDesigner/) 279 | 280 | [AlloyClip](https://github.com/AlloyTeam/AlloyClip) 281 | 282 | [AlloyPhoto](https://github.com/AlloyTeam/AlloyPhoto) 283 | -------------------------------------------------------------------------------- /src/module/tools.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 图像工具方法 不会返回AI本身,会得到图像的一些特征 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("Tools",function(P){ 9 | 10 | var M = { 11 | //获得到图像的色系特征 12 | getColor: { 13 | process: function(imgData, args){ 14 | 15 | var dM = P.lib.dorsyMath; 16 | var xyToIFun = dM.xyToIFun(imgData.width), i; 17 | 18 | var sum = [0, 0, 0]; 19 | 20 | 21 | var level = 50; 22 | var every = Math.PI * 2 / level, n; 23 | 24 | var result = []; 25 | 26 | //在HSI空间应用 27 | dM.applyInHSI(imgData, function(obj, rColor, alpha){ 28 | if(alpha > 128){ 29 | n = parseInt(obj.H / every); 30 | 31 | if(result[n]){ 32 | }else{ 33 | result[n] = []; 34 | } 35 | 36 | result[n].push([obj.S, obj.I]); 37 | } 38 | 39 | }); 40 | 41 | var t = 3; 42 | 43 | //计算出最大的level分区 44 | var max = 0, maxI = 0;; 45 | for(var i = 0; i < level; i ++){ 46 | if(result[i] && result[i].length > max){ 47 | max = result[i].length; 48 | maxI = i; 49 | } 50 | } 51 | 52 | //计算平均饱和度与灰度 53 | var sumS = 0, avS, sumI = 0, avI; 54 | for(var i = 0; i < result[maxI].length; i ++){ 55 | sumS += result[maxI][i][0]; 56 | sumI += result[maxI][i][1]; 57 | } 58 | 59 | avS = sumS / result[maxI].length; 60 | avI = sumI / result[maxI].length; 61 | 62 | /* 63 | var dResult = [], ddResult = [0]; 64 | //计算微分 65 | for(var i = 1; i < level; i ++){ 66 | dResult[i] = result[i] - result[i - 1]; 67 | } 68 | 69 | //计算2次微分 70 | for(var i = 2; i < level; i ++){ 71 | ddResult[i] = dResult[i] - dResult[i - 1]; 72 | } 73 | 74 | var rect2 = $AI(400, 400); 75 | rect2.ctx(function(){ 76 | this.fillStyle = "#000"; 77 | this.moveTo(0, 200); 78 | this.lineTo(400, 200); 79 | this.stroke(); 80 | 81 | this.moveTo(0, 200); 82 | for(var i = 0; i < result.length; i ++){ 83 | var x = i / result.length * 400; 84 | var y = 400 - (result[i] / 100 + 200); 85 | 86 | this.lineTo(x, y); 87 | this.fillRect(x - 2, y - 2, 4, 4); 88 | } 89 | 90 | this.stroke(); 91 | }).show(); 92 | 93 | $AI(400, 100).show(); 94 | 95 | rect2.ctx(function(){ 96 | this.moveTo(0, 200); 97 | this.lineTo(400, 200); 98 | this.stroke(); 99 | 100 | this.fillStyle = "red"; 101 | 102 | this.moveTo(0, 200); 103 | for(var i = 1; i < dResult.length; i ++){ 104 | var x = i / dResult.length * 400; 105 | var y = 400 - (dResult[i] / 100 + 200); 106 | 107 | this.lineTo(x, y); 108 | this.fillRect(x - 2, y - 2, 4, 4); 109 | } 110 | 111 | this.stroke(); 112 | }).show(); 113 | 114 | /* 115 | var rect3 = $AI(400, 400); 116 | rect3.ctx(function(){ 117 | this.moveTo(0, 200); 118 | this.lineTo(400, 200); 119 | this.stroke(); 120 | 121 | this.moveTo(0, 200); 122 | for(var i = 1; i < ddResult.length; i ++){ 123 | var x = i / ddResult.length * 400; 124 | var y = 400 - (ddResult[i] / 1 + 200); 125 | 126 | this.lineTo(x, y); 127 | } 128 | 129 | this.stroke(); 130 | }).show(); 131 | */ 132 | 133 | //计算出现频率最大的色相 134 | var maxH = maxI * every; 135 | 136 | var rgb = dM.HSIToRGB(maxH, avS, avI); 137 | 138 | /* 139 | var all = this.width * this.height * 3; 140 | var r = parseInt(sum[0] / all); 141 | var g = parseInt(sum[1] / all); 142 | var b = parseInt(sum[2] / all); 143 | */ 144 | 145 | var color = "rgb(" + parseInt(rgb.R) + "," + parseInt(rgb.G) + "," + parseInt(rgb.B) + ")"; 146 | return color; 147 | } 148 | }, 149 | 150 | toText: { 151 | process: function(imgData, args){ 152 | var data = imgData.data, 153 | width = imgData.width, 154 | height = imgData.height, 155 | averageG, 156 | 157 | //灰度串 158 | str = args[0] || ".:;!#@", 159 | 160 | //记录位置信息Arr 161 | positionArr = [], 162 | 163 | //结果字符 164 | resultStr = ""; 165 | 166 | console.log(str); 167 | 168 | var dM = P.lib.dorsyMath; 169 | var xyToIFun = dM.xyToIFun(imgData.width); 170 | 171 | //创建div串 172 | var i, everyLevel = 255 / str.length, j; 173 | for(var x = 0; x < width; x += 1){ 174 | for(var y = 0; y < height; y += 1){ 175 | i = xyToIFun(x, y, 0); 176 | averageG = (data[i] + data[i + 1] + data[i + 2]) / 3; 177 | 178 | j = parseInt(averageG / everyLevel); 179 | 180 | resultStr += str[j]; 181 | } 182 | 183 | resultStr += "
"; 184 | } 185 | 186 | return resultStr; 187 | } 188 | } 189 | }; 190 | 191 | return M; 192 | 193 | }); 194 | 195 | })("psLib"); 196 | -------------------------------------------------------------------------------- /src/module/alteration/seletiveColor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: 可选颜色 4 | * @参考:http://wenku.baidu.com/view/e32d41ea856a561252d36f0b.html 5 | * 6 | */ 7 | ;(function(Ps){ 8 | 9 | window[Ps].module("Alteration.selectiveColor",function(P){ 10 | 11 | var M = { 12 | process: function(imgData, arg){//调节亮度对比度 13 | //选择的颜色 14 | var color = arg[0]; 15 | 16 | //百分数 17 | var C = arg[1]; 18 | var M = arg[2]; 19 | var Y = arg[3]; 20 | var K = arg[4]; 21 | 22 | //是否相对 23 | var isRelative = arg[5] || 0; 24 | 25 | var maxColorMap = { 26 | red: "R", 27 | green: "G", 28 | blue: "B", 29 | "红色": "R", 30 | "绿色": "G", 31 | "蓝色": "B" 32 | }; 33 | 34 | var minColorMap = { 35 | cyan: "R", 36 | magenta: "G", 37 | yellow: "B", 38 | "青色": "R", 39 | "洋红": "G", 40 | "黄色": "B" 41 | }; 42 | 43 | //检查是否是被选中的颜色 44 | var checkSelectedColor = function(colorObj){ 45 | if(maxColorMap[color]){ 46 | return Math.max(colorObj.R, colorObj.G, colorObj.B) == colorObj[maxColorMap[color]]; 47 | }else if(minColorMap[color]){ 48 | return Math.min(colorObj.R, colorObj.G, colorObj.B) == colorObj[minColorMap[color]]; 49 | }else if(color == "black" || color == "黑色"){ 50 | return Math.min(colorObj.R, colorObj.G, colorObj.B) < 128; 51 | }else if(color == "white" || color == "白色"){ 52 | return Math.max(colorObj.R, colorObj.G, colorObj.B) > 128; 53 | }else if(color == "中性色"){ 54 | return ! ((Math.max(colorObj.R, colorObj.G, colorObj.B) < 1) || (Math.min(colorObj.R, colorObj.G, colorObj.B) > 224)); 55 | } 56 | }; 57 | 58 | var upLimit = 0; 59 | var lowLimit = 0; 60 | var limit = 0; 61 | 62 | var alterNum = [C, M, Y, K]; 63 | for(var x = 0, w = imgData.width; x < w; x ++){ 64 | for(var y = 0, h = imgData.height; y < h; y ++){ 65 | P.lib.dorsyMath.xyCal(imgData, x, y, function(R, G, B){ 66 | var colorObj = { 67 | R: R, 68 | G: G, 69 | B: B 70 | }; 71 | 72 | var colorArr = [R, G, B]; 73 | var resultArr =[]; 74 | 75 | if(checkSelectedColor(colorObj)){ 76 | if(maxColorMap[color]){ 77 | var maxColor = maxColorMap[color]; 78 | 79 | var middleValue = R + G + B - Math.max(R, G, B) - Math.min(R, G, B); 80 | limit = colorObj[maxColor] - middleValue; 81 | }else if(minColorMap[color]){ 82 | var minColor = minColorMap[color]; 83 | 84 | var middleValue = R + G + B - Math.max(R, G, B) - Math.min(R, G, B); 85 | limit = middleValue - colorObj[minColor] ; 86 | }else if(color == "black" || color == "黑色"){ 87 | limit = parseInt(127.5 - Math.max(R, G, B)) * 2; 88 | }else if(color == "white" || color == "白色"){ 89 | limit = parseInt(Math.min(R, G, B) - 127.5) * 2; 90 | }else if(color == "中性色"){ 91 | limit = 255 - (Math.abs(Math.max(R, G, B) - 127.5) + Math.abs(Math.min(R, G, B) - 127.5)); 92 | }else{ 93 | return; 94 | } 95 | 96 | for(var i = 0; i < 3; i ++){ 97 | //可减少到的量 98 | var lowLimitDelta = parseInt(limit * (colorArr[i] / 255)); 99 | var lowLimit = colorArr[i] - lowLimitDelta; 100 | 101 | //可增加到的量 102 | var upLimitDelta = parseInt(limit * (1 - colorArr[i] / 255)); 103 | var upLimit = colorArr[i] + upLimitDelta; 104 | 105 | //将黑色算进去 得到影响百分比因子 106 | var factor = (alterNum[i] + K + alterNum[i] * K); 107 | 108 | //相对调节 109 | if(isRelative){ 110 | //如果分量大于128 减少量=增加量 111 | if(colorArr[i] > 128){ 112 | lowLimitDelta = upLimitDelta; 113 | } 114 | 115 | //先算出黑色导致的原始增量 116 | if(K > 0){ 117 | var realUpLimit = colorArr[i] - K * lowLimitDelta; 118 | }else{ 119 | var realUpLimit = colorArr[i] - K * upLimitDelta; 120 | } 121 | 122 | //标准化 123 | if(realUpLimit > upLimit) realUpLimit = upLimit; 124 | if(realUpLimit < lowLimit) realUpLimit = lowLimit; 125 | 126 | upLimitDelta = upLimit - realUpLimit; 127 | lowLimitDelta = realUpLimit - lowLimit; 128 | 129 | if(K < 0){ 130 | lowLimitDelta = upLimitDelta; 131 | }else{ 132 | } 133 | 134 | //> 0表明在减少 135 | if(alterNum[i] > 0){ 136 | realUpLimit -= alterNum[i] * lowLimitDelta; 137 | }else{ 138 | realUpLimit -= alterNum[i] * upLimitDelta; 139 | } 140 | 141 | 142 | }else{ 143 | 144 | //现在量 145 | var realUpLimit = limit * - factor + colorArr[i]; 146 | 147 | } 148 | 149 | if(realUpLimit > upLimit) realUpLimit = upLimit; 150 | if(realUpLimit < lowLimit) realUpLimit = lowLimit; 151 | 152 | resultArr[i] = realUpLimit; 153 | } 154 | 155 | return resultArr; 156 | } 157 | });//end xyCal 158 | }//end forY 159 | }//end forX 160 | 161 | return imgData; 162 | 163 | }//end process Method 164 | };//end M defination 165 | 166 | return M; 167 | }); 168 | 169 | })("psLib"); 170 | -------------------------------------------------------------------------------- /src/other/binaryajax.js: -------------------------------------------------------------------------------- 1 | 2 | var BinaryFile = function(strData, iDataOffset, iDataLength) { 3 | var data = strData; 4 | var dataOffset = iDataOffset || 0; 5 | var dataLength = 0; 6 | 7 | this.getRawData = function() { 8 | return data; 9 | } 10 | 11 | if (typeof strData == "string") { 12 | dataLength = iDataLength || data.length; 13 | 14 | this.getByteAt = function(iOffset) { 15 | return data.charCodeAt(iOffset + dataOffset) & 0xFF; 16 | } 17 | 18 | this.getBytesAt = function(iOffset, iLength) { 19 | var aBytes = []; 20 | 21 | for (var i = 0; i < iLength; i++) { 22 | aBytes[i] = data.charCodeAt((iOffset + i) + dataOffset) & 0xFF 23 | }; 24 | 25 | return aBytes; 26 | } 27 | } else if (typeof strData == "unknown") { 28 | dataLength = iDataLength || IEBinary_getLength(data); 29 | 30 | this.getByteAt = function(iOffset) { 31 | return IEBinary_getByteAt(data, iOffset + dataOffset); 32 | } 33 | 34 | this.getBytesAt = function(iOffset, iLength) { 35 | return new VBArray(IEBinary_getBytesAt(data, iOffset + dataOffset, iLength)).toArray(); 36 | } 37 | } 38 | 39 | this.getLength = function() { 40 | return dataLength; 41 | } 42 | 43 | this.getSByteAt = function(iOffset) { 44 | var iByte = this.getByteAt(iOffset); 45 | if (iByte > 127) 46 | return iByte - 256; 47 | else 48 | return iByte; 49 | } 50 | 51 | this.getShortAt = function(iOffset, bBigEndian) { 52 | var iShort = bBigEndian ? 53 | (this.getByteAt(iOffset) << 8) + this.getByteAt(iOffset + 1) 54 | : (this.getByteAt(iOffset + 1) << 8) + this.getByteAt(iOffset) 55 | if (iShort < 0) iShort += 65536; 56 | return iShort; 57 | } 58 | this.getSShortAt = function(iOffset, bBigEndian) { 59 | var iUShort = this.getShortAt(iOffset, bBigEndian); 60 | if (iUShort > 32767) 61 | return iUShort - 65536; 62 | else 63 | return iUShort; 64 | } 65 | this.getLongAt = function(iOffset, bBigEndian) { 66 | var iByte1 = this.getByteAt(iOffset), 67 | iByte2 = this.getByteAt(iOffset + 1), 68 | iByte3 = this.getByteAt(iOffset + 2), 69 | iByte4 = this.getByteAt(iOffset + 3); 70 | 71 | var iLong = bBigEndian ? 72 | (((((iByte1 << 8) + iByte2) << 8) + iByte3) << 8) + iByte4 73 | : (((((iByte4 << 8) + iByte3) << 8) + iByte2) << 8) + iByte1; 74 | if (iLong < 0) iLong += 4294967296; 75 | return iLong; 76 | } 77 | this.getSLongAt = function(iOffset, bBigEndian) { 78 | var iULong = this.getLongAt(iOffset, bBigEndian); 79 | if (iULong > 2147483647) 80 | return iULong - 4294967296; 81 | else 82 | return iULong; 83 | } 84 | 85 | this.getStringAt = function(iOffset, iLength) { 86 | var aStr = []; 87 | 88 | var aBytes = this.getBytesAt(iOffset, iLength); 89 | for (var j=0; j < iLength; j++) { 90 | aStr[j] = String.fromCharCode(aBytes[j]); 91 | } 92 | return aStr.join(""); 93 | } 94 | 95 | this.getCharAt = function(iOffset) { 96 | return String.fromCharCode(this.getByteAt(iOffset)); 97 | } 98 | this.toBase64 = function() { 99 | return window.btoa(data); 100 | } 101 | this.fromBase64 = function(strBase64) { 102 | data = window.atob(strBase64); 103 | } 104 | } 105 | 106 | 107 | var BinaryAjax = (function() { 108 | 109 | function createRequest() { 110 | var oHTTP = null; 111 | if (window.ActiveXObject) { 112 | oHTTP = new ActiveXObject("Microsoft.XMLHTTP"); 113 | } else if (window.XMLHttpRequest) { 114 | oHTTP = new XMLHttpRequest(); 115 | } 116 | return oHTTP; 117 | } 118 | 119 | function getHead(strURL, fncCallback, fncError) { 120 | var oHTTP = createRequest(); 121 | if (oHTTP) { 122 | if (fncCallback) { 123 | if (typeof(oHTTP.onload) != "undefined") { 124 | oHTTP.onload = function() { 125 | if (oHTTP.status == "200") { 126 | fncCallback(this); 127 | } else { 128 | if (fncError) fncError(); 129 | } 130 | oHTTP = null; 131 | }; 132 | } else { 133 | oHTTP.onreadystatechange = function() { 134 | if (oHTTP.readyState == 4) { 135 | if (oHTTP.status == "200") { 136 | fncCallback(this); 137 | } else { 138 | if (fncError) fncError(); 139 | } 140 | oHTTP = null; 141 | } 142 | }; 143 | } 144 | } 145 | oHTTP.open("HEAD", strURL, true); 146 | oHTTP.send(null); 147 | } else { 148 | if (fncError) fncError(); 149 | } 150 | } 151 | 152 | function sendRequest(strURL, fncCallback, fncError, aRange, bAcceptRanges, iFileSize) { 153 | var oHTTP = createRequest(); 154 | if (oHTTP) { 155 | 156 | var iDataOffset = 0; 157 | if (aRange && !bAcceptRanges) { 158 | iDataOffset = aRange[0]; 159 | } 160 | var iDataLen = 0; 161 | if (aRange) { 162 | iDataLen = aRange[1]-aRange[0]+1; 163 | } 164 | 165 | if (fncCallback) { 166 | if (typeof(oHTTP.onload) != "undefined") { 167 | oHTTP.onload = function() { 168 | if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") { 169 | oHTTP.binaryResponse = new BinaryFile(oHTTP.responseText, iDataOffset, iDataLen); 170 | oHTTP.fileSize = iFileSize || oHTTP.getResponseHeader("Content-Length"); 171 | fncCallback(oHTTP); 172 | } else { 173 | if (fncError) fncError(); 174 | } 175 | oHTTP = null; 176 | }; 177 | } else { 178 | oHTTP.onreadystatechange = function() { 179 | if (oHTTP.readyState == 4) { 180 | if (oHTTP.status == "200" || oHTTP.status == "206" || oHTTP.status == "0") { 181 | // IE6 craps if we try to extend the XHR object 182 | var oRes = { 183 | status : oHTTP.status, 184 | // IE needs responseBody, Chrome/Safari needs responseText 185 | binaryResponse : new BinaryFile( 186 | typeof oHTTP.responseBody == "unknown" ? oHTTP.responseBody : oHTTP.responseText, iDataOffset, iDataLen 187 | ), 188 | fileSize : iFileSize || oHTTP.getResponseHeader("Content-Length") 189 | }; 190 | fncCallback(oRes); 191 | } else { 192 | if (fncError) fncError(); 193 | } 194 | oHTTP = null; 195 | } 196 | }; 197 | } 198 | } 199 | oHTTP.open("GET", strURL, true); 200 | 201 | if (oHTTP.overrideMimeType) oHTTP.overrideMimeType('text/plain; charset=x-user-defined'); 202 | 203 | if (aRange && bAcceptRanges) { 204 | oHTTP.setRequestHeader("Range", "bytes=" + aRange[0] + "-" + aRange[1]); 205 | } 206 | 207 | oHTTP.setRequestHeader("If-Modified-Since", "Sat, 1 Jan 1970 00:00:00 GMT"); 208 | 209 | oHTTP.send(null); 210 | } else { 211 | if (fncError) fncError(); 212 | } 213 | } 214 | 215 | return function(strURL, fncCallback, fncError, aRange) { 216 | 217 | if (aRange) { 218 | getHead( 219 | strURL, 220 | function(oHTTP) { 221 | var iLength = parseInt(oHTTP.getResponseHeader("Content-Length"),10); 222 | var strAcceptRanges = oHTTP.getResponseHeader("Accept-Ranges"); 223 | 224 | var iStart, iEnd; 225 | iStart = aRange[0]; 226 | if (aRange[0] < 0) 227 | iStart += iLength; 228 | iEnd = iStart + aRange[1] - 1; 229 | 230 | sendRequest(strURL, fncCallback, fncError, [iStart, iEnd], (strAcceptRanges == "bytes"), iLength); 231 | } 232 | ); 233 | 234 | } else { 235 | sendRequest(strURL, fncCallback, fncError); 236 | } 237 | } 238 | 239 | }()); 240 | 241 | /* 242 | document.write( 243 | "\r\n" 251 | ); 252 | */ 253 | 254 | document.write( 255 | "\r\n" 271 | ); -------------------------------------------------------------------------------- /nsrc/alloyimage.layer.js: -------------------------------------------------------------------------------- 1 | AIDefine('layer', [], function(){ 2 | var Add = { 3 | 4 | //isFast用于快速,适用于中间处理 5 | add: function(lowerData, upperData, method, alpha, dx, dy, isFast, channel){ 6 | var l = lowerData.data, 7 | u = upperData.data, 8 | 9 | dx = dx || 0, 10 | dy = dy || 0, 11 | alpha = alpha || 1,//alpha 范围为0 - 100 12 | isFast = isFast || false, 13 | channel = channel || "RGB"; 14 | 15 | if(!(/[RGB]+/.test(channel))){ 16 | channel = "RGB"; 17 | } 18 | 19 | var channelString = channel.replace("R","0").replace("G","1").replace("B","2"), 20 | jump = 1, 21 | result, 22 | width = lowerData.width, 23 | height = lowerData.height, 24 | upperLength = u.length, 25 | upperWidth = upperData.width, 26 | upperHeight = upperData.height, 27 | 28 | indexOfArr = [ 29 | channelString.indexOf("0") > -1, 30 | channelString.indexOf("1") > -1, 31 | channelString.indexOf("2") > -1 32 | ], 33 | everyJump = 4 * jump; 34 | 35 | /* 36 | if(isFast){ 37 | jump = 1; 38 | } 39 | */ 40 | 41 | var ii, row, col, uRow, uCol, uIi, uI; 42 | 43 | //计算重叠部分x ,y范围 44 | var xMin, yMin, xMax, yMax; 45 | 46 | var uXMin = dx; 47 | var uXMax = dx + upperWidth; 48 | var uYMin = dy; 49 | var uYMax = dy + upperHeight; 50 | 51 | if(uXMin > width){ 52 | return; 53 | }else if(uXMin < 0){ 54 | uXMin = 0; 55 | } 56 | 57 | if(uXMax < 0){ 58 | return; 59 | }else if(uXMax > width){ 60 | uXMax = width; 61 | } 62 | 63 | if(uYMin > height){ 64 | return; 65 | }else if(uYMin < 0){ 66 | uYMin = 0; 67 | } 68 | 69 | if(uYMax < 0){ 70 | return; 71 | }else if(uYMax > height){ 72 | uYMax = height; 73 | } 74 | 75 | 76 | var currRow, upperY, upperRow; 77 | for(var y = uYMin; y < uYMax; y ++){ 78 | currRow = y * width; 79 | upperY = y - dy; 80 | upperRow = upperY * upperWidth; 81 | 82 | for(var x = uXMin; x < uXMax; x ++){ 83 | //计算此时对应的upperX,Y 84 | var upperX = x - dx; 85 | 86 | //计算此时的i 87 | var i = (currRow + x) * 4; 88 | 89 | //计算此时的upperI 90 | var uI = (upperRow + upperX) * 4; 91 | 92 | //for(var i = 0, n = l.length; i < n; i += everyJump){ 93 | 94 | //ii = i / 4; 95 | 96 | //得到当前点的坐标 y分量 97 | //row = ~~(ii / width); 98 | //col = ii % width; 99 | 100 | //uRow = row - dy; 101 | //uCol = col - dx; 102 | 103 | //uIi = uRow * upperWidth + uCol; 104 | //uI = uIi * 4; 105 | 106 | //if(uI >= 0 && uI < (upperLength - 4) && uCol < upperWidth && uCol >= 0){ 107 | 108 | //l[i + 3] = u[uI + 3];//透明度 109 | for(var j = 0; j < 3; j ++){ 110 | 111 | //若此点透明则不计算 112 | if(u[uI + 3] == 0) break; 113 | else l[i + 3] = u[uI + 3]; 114 | 115 | switch(method){ 116 | case "颜色减淡" : 117 | if(indexOfArr[j]){ 118 | result = l[i + j] + (l[i + j] * u[uI + j]) / (255 - u[uI + j]); 119 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 120 | } 121 | break; 122 | 123 | case "变暗": 124 | if(indexOfArr[j]){ 125 | result = l[i + j] < u[uI + j] ? l[i + j] : u[uI + j]; 126 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 127 | } 128 | break; 129 | 130 | case "变亮": 131 | if(indexOfArr[j]){ 132 | result = l[i + j] > u[uI + j] ? l[i + j] : u[uI + j]; 133 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 134 | } 135 | break; 136 | 137 | case "正片叠底": 138 | if(indexOfArr[j]){ 139 | result = ~~((l[i + j] * u[uI + j]) / 255); 140 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 141 | } 142 | break; 143 | 144 | case "滤色" : 145 | if(indexOfArr[j]){ 146 | result = ~~(255 - (255 - l[i + j]) * (255 - u[uI + j]) / 255); 147 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 148 | } 149 | break; 150 | 151 | case "叠加": 152 | if(indexOfArr[j]){ 153 | if(l[i + j] <= 127.5){ 154 | result = l[i + j] * u[uI + j] / 127.5; 155 | }else{ 156 | result = 255 - (255 - l[i + j]) * (255 - u[uI + j]) / 127.5; 157 | } 158 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 159 | } 160 | break; 161 | 162 | case "强光": 163 | if(indexOfArr[j]){ 164 | if(u[uI + j] <= 127.5){ 165 | result = l[i + j] * u[uI + j] / 127.5; 166 | }else{ 167 | result = l[i + j] + (255 - l[i + j]) * (u[uI + j] - 127.5) / 127.5; 168 | } 169 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 170 | } 171 | break; 172 | 173 | case "差值": 174 | if(indexOfArr[j]){ 175 | result = l[i + j] > u[uI + j] ? l[i + j] - u[uI + j] : u[uI + j] - l[i + j]; 176 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 177 | } 178 | break; 179 | 180 | case "排除": 181 | if(indexOfArr[j]){ 182 | result = l[i + j] + u[uI + j] - (l[i + j] * u[uI + j]) / 127.5; 183 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 184 | } 185 | break; 186 | 187 | case "点光": 188 | if(indexOfArr[j]){ 189 | if(l[i + j] < (2 * u[uI + j] - 255)){ 190 | result = 2 * u[uI + j] - 255; 191 | }else if(l[i + j] < 2 * u[uI + j]){ 192 | result = l[i + j]; 193 | }else{ 194 | result = 2 * u[uI + j]; 195 | } 196 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 197 | } 198 | break; 199 | 200 | case "颜色加深": 201 | if(indexOfArr[j]){ 202 | result = 255 - 255 * (255 - l[i + j]) / u[uI + j]; 203 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 204 | } 205 | break; 206 | 207 | case "线性加深": 208 | if(indexOfArr[j]){ 209 | var tempR = l[i + j] + u[uI + j]; 210 | result = tempR > 255 ? tempR - 255 : 0; 211 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 212 | } 213 | break; 214 | 215 | case "线性减淡": 216 | if(indexOfArr[j]){ 217 | var tempR = l[i + j] + u[uI + j]; 218 | result = tempR > 255 ? 255 : tempR; 219 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 220 | } 221 | break; 222 | 223 | case "柔光": 224 | if(indexOfArr[j]){ 225 | if(u[uI + j] < 127.5){ 226 | result = ((2 * u[uI + j] - 255) * (255 - l[i + j]) / (255 * 255) + 1) * l[i + j]; 227 | }else{ 228 | result = (2 * u[uI + j] - 255) * (Math.sqrt(l[i + j] / 255) - l[i + j] / 255) + l[i + j]; 229 | } 230 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 231 | } 232 | break; 233 | 234 | case "亮光": 235 | if(indexOfArr[j]){ 236 | if(u[uI + j] < 127.5){ 237 | result = (1 - (255 - l[i + j]) / (2 * u[uI + j])) * 255; 238 | }else{ 239 | result = l[i + j] / (2 * (1 - u[uI + j] / 255)); 240 | } 241 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 242 | } 243 | break; 244 | 245 | case "线性光": 246 | if(indexOfArr[j]){ 247 | var tempR = l[i + j] + 2 * u[uI + j] - 255; 248 | result = tempR > 255 ? 255 : tempR; 249 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 250 | } 251 | break; 252 | 253 | case "实色混合": 254 | if(indexOfArr[j]){ 255 | if(u[uI + j] < (255 - l[i + j])){ 256 | result = 0; 257 | }else{ 258 | result = 255; 259 | } 260 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 261 | } 262 | break; 263 | 264 | default: 265 | if(indexOfArr[j]){ 266 | result = u[uI + j]; 267 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 268 | } 269 | }//end switch 270 | }//end for 271 | }//end y 272 | 273 | }//end x 274 | 275 | return lowerData; 276 | } 277 | }; 278 | 279 | return Add; 280 | }); 281 | -------------------------------------------------------------------------------- /src/module/addLayer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description: Main add 4 | * 5 | */ 6 | ;(function(Ps){ 7 | 8 | window[Ps].module("addLayer",function(P){ 9 | 10 | var Add = { 11 | 12 | //isFast用于快速,适用于中间处理 13 | add: function(lowerData, upperData, method, alpha, dx, dy, isFast, channel){ 14 | var l = lowerData.data, 15 | u = upperData.data, 16 | 17 | dx = dx || 0, 18 | dy = dy || 0, 19 | alpha = alpha || 1,//alpha 范围为0 - 100 20 | isFast = isFast || false, 21 | channel = channel || "RGB"; 22 | 23 | if(!(/[RGB]+/.test(channel))){ 24 | channel = "RGB"; 25 | } 26 | 27 | var channelString = channel.replace("R","0").replace("G","1").replace("B","2"), 28 | jump = 1, 29 | result, 30 | width = lowerData.width, 31 | height = lowerData.height, 32 | upperLength = u.length, 33 | upperWidth = upperData.width, 34 | upperHeight = upperData.height, 35 | 36 | indexOfArr = [ 37 | channelString.indexOf("0") > -1, 38 | channelString.indexOf("1") > -1, 39 | channelString.indexOf("2") > -1 40 | ], 41 | everyJump = 4 * jump; 42 | 43 | /* 44 | if(isFast){ 45 | jump = 1; 46 | } 47 | */ 48 | 49 | var ii, row, col, uRow, uCol, uIi, uI; 50 | 51 | //计算重叠部分x ,y范围 52 | var xMin, yMin, xMax, yMax; 53 | 54 | var uXMin = dx; 55 | var uXMax = dx + upperWidth; 56 | var uYMin = dy; 57 | var uYMax = dy + upperHeight; 58 | 59 | if(uXMin > width){ 60 | return; 61 | }else if(uXMin < 0){ 62 | uXMin = 0; 63 | } 64 | 65 | if(uXMax < 0){ 66 | return; 67 | }else if(uXMax > width){ 68 | uXMax = width; 69 | } 70 | 71 | if(uYMin > height){ 72 | return; 73 | }else if(uYMin < 0){ 74 | uYMin = 0; 75 | } 76 | 77 | if(uYMax < 0){ 78 | return; 79 | }else if(uYMax > height){ 80 | uYMax = height; 81 | } 82 | 83 | 84 | var currRow, upperY, upperRow; 85 | for(var y = uYMin; y < uYMax; y ++){ 86 | currRow = y * width; 87 | upperY = y - dy; 88 | upperRow = upperY * upperWidth; 89 | 90 | for(var x = uXMin; x < uXMax; x ++){ 91 | //计算此时对应的upperX,Y 92 | var upperX = x - dx; 93 | 94 | //计算此时的i 95 | var i = (currRow + x) * 4; 96 | 97 | //计算此时的upperI 98 | var uI = (upperRow + upperX) * 4; 99 | 100 | //for(var i = 0, n = l.length; i < n; i += everyJump){ 101 | 102 | //ii = i / 4; 103 | 104 | //得到当前点的坐标 y分量 105 | //row = ~~(ii / width); 106 | //col = ii % width; 107 | 108 | //uRow = row - dy; 109 | //uCol = col - dx; 110 | 111 | //uIi = uRow * upperWidth + uCol; 112 | //uI = uIi * 4; 113 | 114 | //if(uI >= 0 && uI < (upperLength - 4) && uCol < upperWidth && uCol >= 0){ 115 | 116 | //l[i + 3] = u[uI + 3];//透明度 117 | for(var j = 0; j < 3; j ++){ 118 | 119 | //若此点透明则不计算 120 | if(u[uI + 3] == 0) break; 121 | else l[i + 3] = u[uI + 3]; 122 | 123 | switch(method){ 124 | case "颜色减淡" : 125 | if(indexOfArr[j]){ 126 | result = l[i + j] + (l[i + j] * u[uI + j]) / (255 - u[uI + j]); 127 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 128 | } 129 | break; 130 | 131 | case "变暗": 132 | if(indexOfArr[j]){ 133 | result = l[i + j] < u[uI + j] ? l[i + j] : u[uI + j]; 134 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 135 | } 136 | break; 137 | 138 | case "变亮": 139 | if(indexOfArr[j]){ 140 | result = l[i + j] > u[uI + j] ? l[i + j] : u[uI + j]; 141 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 142 | } 143 | break; 144 | 145 | case "正片叠底": 146 | if(indexOfArr[j]){ 147 | result = ~~((l[i + j] * u[uI + j]) / 255); 148 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 149 | } 150 | break; 151 | 152 | case "滤色" : 153 | if(indexOfArr[j]){ 154 | result = ~~(255 - (255 - l[i + j]) * (255 - u[uI + j]) / 255); 155 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 156 | } 157 | break; 158 | 159 | case "叠加": 160 | if(indexOfArr[j]){ 161 | if(l[i + j] <= 127.5){ 162 | result = l[i + j] * u[uI + j] / 127.5; 163 | }else{ 164 | result = 255 - (255 - l[i + j]) * (255 - u[uI + j]) / 127.5; 165 | } 166 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 167 | } 168 | break; 169 | 170 | case "强光": 171 | if(indexOfArr[j]){ 172 | if(u[uI + j] <= 127.5){ 173 | result = l[i + j] * u[uI + j] / 127.5; 174 | }else{ 175 | result = l[i + j] + (255 - l[i + j]) * (u[uI + j] - 127.5) / 127.5; 176 | } 177 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 178 | } 179 | break; 180 | 181 | case "差值": 182 | if(indexOfArr[j]){ 183 | result = l[i + j] > u[uI + j] ? l[i + j] - u[uI + j] : u[uI + j] - l[i + j]; 184 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 185 | } 186 | break; 187 | 188 | case "排除": 189 | if(indexOfArr[j]){ 190 | result = l[i + j] + u[uI + j] - (l[i + j] * u[uI + j]) / 127.5; 191 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 192 | } 193 | break; 194 | 195 | case "点光": 196 | if(indexOfArr[j]){ 197 | if(l[i + j] < (2 * u[uI + j] - 255)){ 198 | result = 2 * u[uI + j] - 255; 199 | }else if(l[i + j] < 2 * u[uI + j]){ 200 | result = l[i + j]; 201 | }else{ 202 | result = 2 * u[uI + j]; 203 | } 204 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 205 | } 206 | break; 207 | 208 | case "颜色加深": 209 | if(indexOfArr[j]){ 210 | result = 255 - 255 * (255 - l[i + j]) / u[uI + j]; 211 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 212 | } 213 | break; 214 | 215 | case "线性加深": 216 | if(indexOfArr[j]){ 217 | var tempR = l[i + j] + u[uI + j]; 218 | result = tempR > 255 ? tempR - 255 : 0; 219 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 220 | } 221 | break; 222 | 223 | case "线性减淡": 224 | if(indexOfArr[j]){ 225 | var tempR = l[i + j] + u[uI + j]; 226 | result = tempR > 255 ? 255 : tempR; 227 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 228 | } 229 | break; 230 | 231 | case "柔光": 232 | if(indexOfArr[j]){ 233 | if(u[uI + j] < 127.5){ 234 | result = ((2 * u[uI + j] - 255) * (255 - l[i + j]) / (255 * 255) + 1) * l[i + j]; 235 | }else{ 236 | result = (2 * u[uI + j] - 255) * (Math.sqrt(l[i + j] / 255) - l[i + j] / 255) + l[i + j]; 237 | } 238 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 239 | } 240 | break; 241 | 242 | case "亮光": 243 | if(indexOfArr[j]){ 244 | if(u[uI + j] < 127.5){ 245 | result = (1 - (255 - l[i + j]) / (2 * u[uI + j])) * 255; 246 | }else{ 247 | result = l[i + j] / (2 * (1 - u[uI + j] / 255)); 248 | } 249 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 250 | } 251 | break; 252 | 253 | case "线性光": 254 | if(indexOfArr[j]){ 255 | var tempR = l[i + j] + 2 * u[uI + j] - 255; 256 | result = tempR > 255 ? 255 : tempR; 257 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 258 | } 259 | break; 260 | 261 | case "实色混合": 262 | if(indexOfArr[j]){ 263 | if(u[uI + j] < (255 - l[i + j])){ 264 | result = 0; 265 | }else{ 266 | result = 255; 267 | } 268 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 269 | } 270 | break; 271 | 272 | default: 273 | if(indexOfArr[j]){ 274 | result = u[uI + j]; 275 | l[i + j] = (1 - alpha) * l[i + j] + (alpha) * result; 276 | } 277 | }//end switch 278 | }//end for 279 | }//end y 280 | 281 | }//end x 282 | 283 | return lowerData; 284 | } 285 | }; 286 | 287 | return Add; 288 | 289 | }); 290 | 291 | })("psLib"); 292 | -------------------------------------------------------------------------------- /src/module/dorsyMath.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @author: Bin Wang 3 | * @description:数学处理模块-core 4 | * FFT 矩阵 复数 Langrange插值 5 | * 6 | */ 7 | ;(function(Ps){ 8 | 9 | window[Ps].module("dorsyMath", function(P){ 10 | 11 | var M = { 12 | FFT1: function(dataArr){ 13 | /* 14 | * @description:快速傅里叶变换 15 | * @按时间抽取 16 | * */ 17 | var size = dataArr.length; 18 | var count = 0; 19 | 20 | //------计算权重W------------ 21 | var W = []; 22 | for(var i = 0; i < size; i ++){ 23 | W[i] = this.exp(-2 * Math.PI * i / size); 24 | } 25 | 26 | 27 | butterflyCal(); 28 | return dataArr; 29 | 30 | //蝶形运算单元 31 | function butterflyCal(){ 32 | count ++; 33 | 34 | //蝶形单元个数 35 | var singleLength = size / Math.pow(2,count); 36 | var everyLength = size / singleLength; 37 | 38 | for(var i = 0; i < singleLength; i ++){ 39 | 40 | //逐次计算蝶形单元 41 | singleButterflyCal(i * everyLength, (i + 1) * everyLength - 1, count); 42 | } 43 | 44 | //如果单元个数大于1继续运算 45 | if(singleLength > 1){ 46 | 47 | //递归 48 | butterflyCal(); 49 | }else{ 50 | } 51 | 52 | } 53 | 54 | //一个蝶形单元 n运算次数 蝶形单元的成对间隔 55 | function singleButterflyCal(start, end, n){ 56 | 57 | var delta = Math.pow(2,n - 1); 58 | 59 | for(var i = start, j = 0; i <= (end - delta); i ++){ 60 | 61 | //i 的运算对 62 | var pairI = i + delta; 63 | 64 | //计算i运算时的权重下标 65 | var currWeightForI = j * size / Math.pow(2,n); 66 | 67 | //计算i的运算对时候的权重 68 | var currWeightForPairI = currWeightForI + size / 4; 69 | 70 | if(!(dataArr[i] instanceof M.C)) dataArr[i] = new M.C(dataArr[i]); 71 | 72 | if(!(dataArr[pairI] instanceof M.C)) dataArr[pairI] = new M.C(dataArr[pairI]); 73 | 74 | var currResultForI = dataArr[i].plus(dataArr[pairI].mutiply(W[currWeightForI])); 75 | var currResultForPairI = dataArr[i].plus(dataArr[pairI].mutiply(W[currWeightForPairI])); 76 | 77 | dataArr[i] = currResultForI; 78 | dataArr[pairI] = currResultForPairI; 79 | 80 | j++; 81 | } 82 | } 83 | 84 | }, 85 | 86 | DFT: function(){ 87 | /* 88 | * @description:离散傅里叶变换 89 | * */ 90 | 91 | }, 92 | 93 | Matrix: function(arr,arg,arg2){ 94 | /* 95 | * @descriptiont:矩阵类 96 | * 构造一个矩阵,当然从原始的数据构造,但具有矩阵的所有基本运算方法 97 | * arr参数可以为矩阵,附加字符串参数为构造的行列如 ([0,0],"3*4") 或("构造3*4的1矩阵") ("构造3*4的0矩阵") 98 | * */ 99 | var resultArr = []; 100 | 101 | if(arg){ 102 | 103 | if(isNaN(arg)){ 104 | var m = /(\d+)\s*\*/.exec(arg)[1]; 105 | var n = /\*\s*(\d+)/.exec(arg)[1]; 106 | }else{ 107 | m = arg; 108 | n = arg2; 109 | } 110 | 111 | //本身二维的 112 | if(arr[0] && arr[0][0]){ 113 | for(var i = 0;i < m;i ++){ 114 | resultArr[i] = []; 115 | for(var j = 0;j < n;j ++){ 116 | resultArr[i][j] = arr[i][j] || 0; 117 | } 118 | } 119 | 120 | //一维的 121 | }else{ 122 | 123 | for(var i = 0;i < m;i ++){ 124 | resultArr[i] = []; 125 | for(var j = 0;j < n;j ++){ 126 | var t = i * n + j; 127 | resultArr[i][j] = arr[i * n + j] || 0; 128 | } 129 | } 130 | 131 | } 132 | 133 | this.m = m; 134 | this.n = n; 135 | 136 | }else{ 137 | this.m = arr.length; 138 | this.n = arr[0].length; 139 | } 140 | 141 | this.data = resultArr; 142 | }, 143 | 144 | C: function(r,i){ 145 | /* 146 | * @description:复数对象 147 | * 148 | * */ 149 | this.r = r || 0;//实部 150 | this.i = i || 0;//虚部 151 | }, 152 | 153 | exp: function(theta,r){// r e^(i * theta) = r cos theta + r i * sin theta 154 | 155 | theta = theta || 0; 156 | r = r || 1; 157 | 158 | var tempC = new M.C(); 159 | tempC.r = r * Math.cos(theta); 160 | tempC.i = r * Math.sin(theta); 161 | 162 | return tempC; 163 | }, 164 | 165 | lagrange: function(xArr,yArr){ 166 | /* 167 | * Lagrange插值 168 | * @usage M.lagrange([1,2],[2,4])(3); 169 | * */ 170 | var num = xArr.length; 171 | function getLk(x,k){//计算lk 172 | var omigaXk = 1; 173 | var omigaX = 1; 174 | for(var i = 0;i < num;i ++){ 175 | if(i != k){ 176 | omigaXk *= xArr[k] - xArr[i]; 177 | omigaX *= x - xArr[i]; 178 | } 179 | } 180 | var lk = omigaX / omigaXk; 181 | return lk; 182 | } 183 | var getY = function(x){ 184 | var L = 0; 185 | for(var k = 0;k < num;k ++){ 186 | var lk = getLk(x,k); 187 | L += yArr[k] * lk; 188 | 189 | } 190 | return L; 191 | }; 192 | return getY; 193 | 194 | }, 195 | 196 | applyMatrix: function(imgData,matrixArr,low){//对图象信号实行掩模算子变换 low为阈值,滤波运算 197 | 198 | low = low || 0; 199 | var data = imgData.data; 200 | var width = imgData.width; 201 | var height = imgData.height; 202 | var matrixSize = matrixArr.length; 203 | var template = new M.Matrix(matrixArr,matrixSize,1); 204 | var tempData = []; 205 | var start = -(Math.sqrt(matrixSize) - 1) / 2; 206 | 207 | for(var i = 0,n = data.length;i < n;i += 4){ 208 | var ii = i / 4; 209 | var row = parseInt(ii / width); 210 | var col = ii % width; 211 | if(row == 0 || col == 0) continue; 212 | 213 | var pixelArr = [[],[],[]]; 214 | for(var k = start;k <= -start;k ++){ 215 | var currRow = row + k; 216 | 217 | for(var kk = start;kk <= -start;kk ++){ 218 | 219 | var currCol = col + kk; 220 | var currI = (currRow * width + currCol) * 4; 221 | 222 | for(var j = 0;j < 3;j ++){ 223 | var tempI = currI + j; 224 | pixelArr[j].push(data[tempI]); 225 | } 226 | 227 | } 228 | 229 | } 230 | 231 | var pixelMatrix = new P.lib.dorsyMath.Matrix(pixelArr,3,matrixSize); 232 | var resultMatrix = pixelMatrix.mutiply(template); 233 | 234 | for(var j = 0;j < 3;j ++){ 235 | tempData[i + j] = resultMatrix.data[j]; 236 | } 237 | tempData[i + 4] = data[i + 4]; 238 | } 239 | 240 | for(var i = 0,n = data.length;i < n;i ++){ 241 | if(tempData[i]){ 242 | data[i] = tempData[i] < low ? tempData[i] : data[i]; 243 | } 244 | } 245 | 246 | return imgData; 247 | }, 248 | 249 | RGBToHSI: function(R,G,B){ 250 | var theta = ((R - G + R - B) / 2) / Math.sqrt((R - G) * (R - G) + (R - B) * (G - B)) || 0; 251 | theta = Math.acos(theta); 252 | var H = B > G ? (2 * Math.PI - theta) : theta; 253 | 254 | if(R + G + B > 0){ 255 | var S = 1 - 3 * Math.min(R,G,B) / (R + G + B); 256 | }else{ 257 | var S = 0; 258 | } 259 | 260 | var I = (R + G + B) / 3; 261 | 262 | if(H > 2 * Math.PI) H = 2 * Math.PI; 263 | if(H < 0) H = 0; 264 | 265 | return { 266 | H: H, 267 | S: S, 268 | I: I 269 | }; 270 | 271 | }, 272 | 273 | HSIToRGB: function(H,S,I){//H为弧度值 274 | //H (-Math.PI , Math.PI) S (-1,1) I (-255,255) 275 | if(H < 0){ 276 | H %= 2 * Math.PI; 277 | H += 2 * Math.PI 278 | }else{ 279 | H %= 2 * Math.PI; 280 | } 281 | 282 | if(H <= Math.PI * 2 / 3){ 283 | var B = I * (1 - S); 284 | var R = I * (1 + S * Math.cos(H) / Math.cos(Math.PI / 3 - H)); 285 | var G = 3 * I - (R + B); 286 | 287 | }else if(H <= Math.PI * 4 / 3){ 288 | H = H - Math.PI * 2 / 3; 289 | 290 | var R = I * (1 - S); 291 | var G = I * (1 + S * Math.cos(H) / Math.cos(Math.PI / 3 - H)); 292 | var B = 3 * I - (G + R); 293 | 294 | }else{ 295 | H = H - Math.PI * 4 / 3; 296 | 297 | var G = I * (1 - S); 298 | var B = I * (1 + S * Math.cos(H) / Math.cos(Math.PI / 3 - H)); 299 | var R = 3 * I - (G + B); 300 | 301 | } 302 | 303 | return { 304 | R: R, 305 | G: G, 306 | B: B 307 | }; 308 | }, 309 | 310 | applyInHSI: function(imgData, func){//在hsi空间上应用func 311 | /* 312 | * function(i){ 313 | * i.H += 3; 314 | * } 315 | * H (-2*Math.PI , 2 * Math.PI) S (-1,1) I (-255,255) 316 | * */ 317 | var colorMap = ["R", "Y", "G", "C", "B", "M"]; 318 | var data = imgData.data; 319 | 320 | var d30 = Math.PI / 6; 321 | var d60 = Math.PI / 3; 322 | for(var i = 0, n = data.length; i < n; i += 4){ 323 | var hsiObj = this.RGBToHSI(data[i], data[i + 1], data[i + 2]); 324 | 325 | //得到颜色属性 326 | var h = hsiObj.H + d30; 327 | var color = ~~ (h / d60); 328 | var rColor = colorMap[color % 6]; 329 | 330 | func(hsiObj, rColor, data[i + 3]); 331 | 332 | if(hsiObj.S > 1) hsiObj.S = 1; 333 | if(hsiObj.S < 0) hsiObj.S = 0; 334 | 335 | var rgbObj = this.HSIToRGB(hsiObj.H,hsiObj.S,hsiObj.I); 336 | data[i] = rgbObj.R; 337 | data[i + 1] = rgbObj.G; 338 | data[i + 2] = rgbObj.B; 339 | } 340 | 341 | }, 342 | 343 | applyInCoordinate: function(imgData,func){//在坐标空间上应用func 344 | /* 345 | * function(dot){ 346 | * 347 | * } 348 | * */ 349 | }, 350 | 351 | //计算两个点之间的距离 352 | //p1 array 353 | //p2 array 354 | distance: function(p1, p2){ 355 | p2 = p2 || [0, 0]; 356 | 357 | p1 = new M.C(p1[0], p1[1]); 358 | p2 = new M.C(p2[0], p2[1]); 359 | 360 | var p3 = p1.minus(p2); 361 | return p3.distance(); 362 | }, 363 | 364 | //将(x,y)的坐标转为单维的i 365 | xyToIFun: function(width){ 366 | return function(x, y, z){ 367 | z = z || 0; 368 | return (y * width + x) * 4 + z; 369 | }; 370 | }, 371 | 372 | //在(x,y)进行运算 373 | //rgbfun 在rgb三个上进行的操作 aFun在alpha进行的操作 374 | //rgbFun: function(r, g, b){ 375 | // return [r, g, b] 376 | // 377 | //} 378 | xyCal: function(imgData, x, y, rgbFun, aFun){ 379 | var xyToIFun = this.xyToIFun(imgData.width); 380 | var j = xyToIFun(x, y, 0); 381 | var data = imgData.data; 382 | var processedData = rgbFun(data[j], data[j + 1], data[j + 2]); 383 | 384 | if(processedData){ 385 | data[j] = processedData[0]; 386 | data[j + 1] = processedData[1]; 387 | data[j + 2] = processedData[2]; 388 | } 389 | 390 | if(aFun){ 391 | data[j + 3] = aFun(data[j + 3]); 392 | } 393 | 394 | } 395 | 396 | }; 397 | 398 | /* 399 | var t = M.RGBToHSI(255,5,25); 400 | var f = M.HSIToRGB(t.H+2 * Math.PI,t.S,t.I); 401 | alert(f.R + "|" + f.G + "|" + f.B); 402 | */ 403 | 404 | M.Matrix.prototype = { 405 | /*m: 0,//数学上传统的m*n矩阵 406 | n: 0, 407 | */ 408 | plus: function(matrix){ 409 | if(this.m != matrix.m || this.n != matrix.n){ 410 | throw new Error("矩阵加法行列不匹配"); 411 | } 412 | 413 | 414 | var tempM = new M.Matrix([],this.m,this.n); 415 | for(var i = 0;i < this.m;i ++){ 416 | for(var j = 0;j < this.n;j ++){ 417 | tempM.data[i][j] = this.data[i][j] + matrix.data[i][j]; 418 | } 419 | } 420 | return tempM; 421 | }, 422 | 423 | minus: function(matrix){ 424 | if(this.m != matrix.m || this.n != matrix.n){ 425 | throw new Error("矩阵减法法行列不匹配"); 426 | } 427 | 428 | 429 | var tempM = new M.Matrix([],this.m,this.n); 430 | for(var i = 0;i < this.m;i ++){ 431 | for(var j = 0;j < this.n;j ++){ 432 | tempM.data[i][j] = this.data[i][j] - matrix.data[i][j]; 433 | } 434 | } 435 | return tempM; 436 | }, 437 | 438 | mutiply: function(matrix){//左乘另一矩阵 439 | if(this.n != matrix.m){ 440 | throw new Error("矩阵乘法行列不匹配"); 441 | } 442 | 443 | 444 | var tempM = new M.Matrix([],this.m,matrix.n); 445 | for(var i = 0;i < this.m;i ++){ 446 | for(var j = 0;j < matrix.n;j ++){ 447 | 448 | var sum = 0; 449 | for(var ii = 0;ii < this.n;ii ++){ 450 | sum += this.data[i][ii] * matrix.data[ii][j]; 451 | } 452 | tempM.data[i][j] = sum; 453 | } 454 | } 455 | return tempM; 456 | 457 | } 458 | }; 459 | 460 | M.C.prototype = { 461 | plus: function(c){ 462 | var tempC = new M.C(); 463 | tempC.r = this.r + c.r; 464 | tempC.i = this.i + c.i; 465 | 466 | return tempC; 467 | }, 468 | minus:function(c){ 469 | var tempC = new M.C(); 470 | tempC.r = this.r - c.r; 471 | tempC.i = this.i - c.i; 472 | 473 | return tempC; 474 | }, 475 | mutiply: function(c){ 476 | var tempC = new M.C(); 477 | tempC.r = this.r * c.r - this.i * c.i; 478 | tempC.i = this.r * c.i + this.i * c.r; 479 | 480 | return tempC; 481 | }, 482 | divide: function(c){ 483 | 484 | var tempC = new M.C(); 485 | 486 | var m = c.mutiply(c.conjugated()); 487 | var f = this.mutiply(c.conjugated()); 488 | tempC.r = f.r / m.r; 489 | tempC.i = f.i / m.r; 490 | 491 | return tempC; 492 | }, 493 | conjugated: function(){//取共轭 494 | var tempC = new M.C(this.r,-this.i); 495 | return tempC; 496 | }, 497 | 498 | //取模 499 | distance: function(){ 500 | return Math.sqrt(this.r * this.r + this.i * this.i); 501 | } 502 | } 503 | /* 504 | var l = new M.Matrix([1,1,2,3],2,2); 505 | var j = new M.Matrix([1,0,1,2],2,2); 506 | var t = l.mutiply(j); 507 | */ 508 | return M; 509 | 510 | }); 511 | 512 | })("psLib"); 513 | -------------------------------------------------------------------------------- /release/alloyimage-1.1.js: -------------------------------------------------------------------------------- 1 | Array.prototype.del=function(h){h.sort();for(var p=this.concat([]),c=h.length-1;0<=c;c--)p=p.slice(0,h[c]).concat(p.slice(h[c]+1));return p};try{HTMLImageElement.prototype.loadOnce=function(h){var p=0;this.onload=function(){p||h.call(this,null);p++}}}catch(e$$10){window={}} 2 | (function(h){function p(){this.readyState&&(this.readyState=0,this.dorsyWorker.startWorker())}var c={lib:[],init:function(){this.require("config")},module:function(a,b){this.lib[a]=b.call(null,this)},require:function(a){var b=this,f=document.createElement("script");document.body.appendChild(f);f.src="./js/module/"+a+".js";f.onload=f.onerror=function(a){b.handlerror(a)}},handlerror:function(){},destroySelf:function(a){delete window[h];throw Error(a);},reflect:function(a,b,f){a=this.lib.config.getModuleName(a); 3 | return this.lib[a].process(b,f)},reflectEasy:function(a){a=this.lib.config.getEasyFun(a);return this.lib.easy.getFun(a)},add:function(a,b,f,i,d,g,c,m){return this.lib.addLayer.add(a,b,f,i,d,g,c,m)},worker:function(){},applyMatrix:function(){}};window[h]=function(a,b,f){if(this instanceof window[h]){this.startTime=+new Date;var i=document.createElement("canvas"),d=i.getContext("2d");isNaN(a)?(i.width=parseInt(a.width),i.height=parseInt(a.height),b=getComputedStyle(a),imgWidth=parseInt(b.getPropertyValue("width")), 4 | imgHeight=parseInt(b.getPropertyValue("height")),isNaN(imgWidth)?d.drawImage(a,0,0):d.drawImage(a,0,0,imgWidth,imgHeight)):(i.width=a,i.height=b,d.fillStyle=f||"#fff",d.fillRect(0,0,a,b));this.canvas=i;this.context=d;this.imgData=d.getImageData(0,0,i.width,i.height);this.name=h+"_"+Math.random();this.canvas.id=this.name;this.layers=[];a=document.createElement("canvas");a.width=i.width;a.height=i.height;this.ctxCanvas=a;this.ctxContext=i.getContext("2d");this.useWorker=c.useWorker;this.readyState= 5 | 1;this.useWorker&&(this.dorsyWorker=c.lib.dorsyWorker(this))}else return new window[h](a,b,f)};window[h].module=function(a,b){c.module(a,b)};window[h].dorsyMath=function(){return c.lib.dorsyMath};window[h].setName=function(a){c.name=a||"alloyimage.js"};window[h].useWorker=function(a){if(window.Worker){a=a||"";/[\/\\]$/.test(a)&&(a+=c.name);""==a&&(a="alloyimage.js");c.useWorker=1;c.path=a;var b=new XMLHttpRequest;b.onreadystatechange=function(){4==b.readyState&&"404"==b.status&&c.destroySelf("AI_ERROR\uff1a\u4f7f\u7528worker\u65f6\uff0cai\u6587\u4ef6\u8def\u5f84\u6307\u5b9a\u9519\u8bef\nAI_ERROR: error occured while using web worker since indicate the wrong path of file ai")}; 6 | b.open("GET",a,!1);b.send()}else this.useWorker=0,console.log("AI_WARNING: \u6d4f\u89c8\u5668\u4e0d\u652f\u6301web worker, \u81ea\u52a8\u5207\u6362\u4e3a\u5355\u7ebf\u7a0b\nAI_WARNING: the brower doesn't support Web Worker")};onmessage=function(a){var a=a.data,b;"act"==a[0]?b=c.reflect(a[1],a[2],a[3]):"add"==a[0]&&(b=c.add.apply(c,a[1]));postMessage(b)};window[h].prototype={act:function(a,b){var f=[],f=Array.prototype.slice.call(arguments,1);this.useWorker?(this.dorsyWorker.queue.push(["act",a,f]), 7 | p.call(this)):c.reflect(a,this.imgData,f);return this},view:function(a,b,f,i,d){var c=this.clone();c.type=1;this.addLayer(c,"\u6b63\u5e38",0,0);c.act(a,b,f,i,d);return this},excute:function(){var a=this.layers,b=a.length;a[b-1]&&1==a[b-1][0].type&&(this.imgData=a[b-1][0].imgData,delete a[b-1])},cancel:function(){var a=this.layers,b=a.length;a[b-1]&&1==a[b-1][0].type&&delete a[b-1]},show:function(a,b,f){if(!f&&this.useWorker)return this.dorsyWorker.queue.push(["show",a,b]),this;if(0==this.layers.length)this.tempPsLib= 8 | {imgData:this.imgData};else{f=new window[h](this.canvas.width,this.canvas.height);f.add(this,"\u6b63\u5e38",0,0,b);this.tempPsLib=f;for(var i=0;id;d++)f[d]>c&&(c=f[d]);for(d=0;255>d;d++)g=f[d]||0,g=a.height-0.8*(g/c)*a.height,b.lineTo(d/256*a.width,g,1,1);b.lineTo(a.width+10,a.height);b.fill()},ps:function(a){var b;b=c.reflectEasy(a).call(this);this.logTime("\u7ec4\u5408\u6548\u679c"+a);return b},logTime:function(a){console.log(a+": "+(+new Date-this.startTime)/1E3+"s")},ctx:function(a){var b= 14 | this.ctxContext;b.putImageData(this.imgData,0,0);a.call(b);this.imgData=b.getImageData(0,0,this.canvas.width,this.canvas.height);return this},notify:function(a){"readyStateOK"==a&&(this.readyState=1)},complete:function(a){this.useWorker?this.dorsyWorker.queue.push(["complete",a]):a()}}})("psLib");window.AlloyImage=$AI=window.psLib;(function(h){window[h].module("ImageEnhance",function(){return{process:function(p){for(var c=p.data,a=0,b=c.length;ae&&0!=j[n+3];e++)switch(d[l+3]=j[n+3],a){case "\u989c\u8272\u51cf\u6de1":m[e]&& 16 | (k=d[l+e]+d[l+e]*j[n+e]/(255-j[n+e]),d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u53d8\u6697":m[e]&&(k=d[l+e]j[n+e]?d[l+e]:j[n+e],d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u6b63\u7247\u53e0\u5e95":m[e]&&(k=parseInt(d[l+e]*j[n+e]/255),d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u6ee4\u8272":m[e]&&(k=parseInt(255-(255-d[l+e])*(255-j[n+e])/255),d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u53e0\u52a0":m[e]&&(k=127.5>=d[l+e]?d[l+e]*j[n+ 17 | e]/127.5:255-(255-d[l+e])*(255-j[n+e])/127.5,d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u5f3a\u5149":m[e]&&(k=127.5>=j[n+e]?d[l+e]*j[n+e]/127.5:d[l+e]+(255-d[l+e])*(j[n+e]-127.5)/127.5,d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u5dee\u503c":m[e]&&(k=d[l+e]>j[n+e]?d[l+e]-j[n+e]:j[n+e]-d[l+e],d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u6392\u9664":m[e]&&(k=d[l+e]+j[n+e]-d[l+e]*j[n+e]/127.5,d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u70b9\u5149":m[e]&&(k=d[l+e]<2*j[n+e]-255?2*j[n+e]-255:d[l+e]<2*j[n+e]?d[l+e]:2*j[n+e], 18 | d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u989c\u8272\u52a0\u6df1":m[e]&&(k=255-255*(255-d[l+e])/j[n+e],d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u7ebf\u6027\u52a0\u6df1":m[e]&&(k=d[l+e]+j[n+e],k=255j[n+e]?((2*j[n+e]-255)*(255-d[l+e])/65025+1)*d[l+e]:(2*j[n+e]-255)*(Math.sqrt(d[l+e]/255)-d[l+e]/255)+d[l+e],d[l+e]=(1-b)*d[l+e]+b*k); 19 | break;case "\u4eae\u5149":m[e]&&(k=127.5>j[n+e]?255*(1-(255-d[l+e])/(2*j[n+e])):d[l+e]/(2*(1-j[n+e]/255)),d[l+e]=(1-b)*d[l+e]+b*k);break;case "\u7ebf\u6027\u5149":m[e]&&(k=d[l+e]+2*j[n+e]-255,k=255g;g++)a[i+g]=(a[i+g]-127.5*(1-b))*f+127.5*(1+b);return p}}})})("psLib"); 21 | (function(h){window[h].module("applyMatrix",function(p){return{process:function(c){for(var a=c.data,b=c.width,f=new p.lib.dorsyMath.Matrix([-2,-4,-4,-4,-2,-4,0,8,0,-4,-4,8,24,8,-4,-4,0,8,0,-4,-2,-4,-4,-4,-2],25,1),i=[],d=0,g=a.length;de;e++)for(var n=m+e,l=-2;3>l;l++)for(var r=4*(n*b+(k+l)),j=0;3>j;j++)h[j].push(a[r+j]);m=(new p.lib.dorsyMath.Matrix(h,3,matrixSize)).mutiply(f);for(j=0;3>j;j++)i[d+j]=m.data[j];i[d+ 22 | 4]=a[d+4]}}d=0;for(g=a.length;dm;m++)b[4*k+m]=b[4*j+m];return p}}})})("psLib"); 26 | (function(h){window[h].module("curve",function(p){return{process:function(c,a){for(var b=p.lib.dorsyMath.lagrange(a[0],a[1]),f=c.data,i=c.width,d=c.height,g=0;gk;k++)f[4*m+k]=b(f[4*m+k]);return c}}})})("psLib"); 27 | (function(h){window[h].module("darkCorner",function(p){return{process:function(c,a){for(var b=parseInt(a[0])||3,f=a[1]||30,i=c.data,d=c.width,g=c.height,j=2*d/3,m=1*g/2,k=p.lib.dorsyMath.distance([j,m]),b=k*(1-b/10),h=0;hl;l++){var r;r=i[4*n+l];var q=(p.lib.dorsyMath.distance([h,e],[j,m])-b)/(k-b);0>q&&(q=0);r=(0*Math.pow(1-q,3)+0.06*q*Math.pow(1-q,2)+3*0.3*q*q*(1-q)+1*Math.pow(q,3))*r*f/255;i[4*n+l]-=r}return c}}})})("psLib"); 28 | (function(h){window[h].module("dorsyMath",function(p){var c={FFT1:function(a){function b(){i++;for(var g=f/Math.pow(2,i),m=f/g,k=0;ke;e++)r[e].push(i[v+e]);n=(new p.lib.dorsyMath.Matrix(r,3,g)).mutiply(b);for(e=0;3> 31 | e;e++)j[k+e]=n.data[e];j[k+4]=i[k+4]}}k=0;for(h=i.length;kb?2*Math.PI-c:c,d=1-3*Math.min(a,b,f)/(a+b+f);c>2*Math.PI&&(c=2*Math.PI);0>c&&(c=0);return{H:c,S:d,I:(a+b+f)/3}},HSIToRGB:function(a,b,f){0>a?(a%=2*Math.PI,a+=2*Math.PI):a%=2*Math.PI;if(a<=2*Math.PI/3)var c=f*(1-b),d=f*(1+b*Math.cos(a)/Math.cos(Math.PI/3-a)),g=3*f-(d+c);else a<=4*Math.PI/3?(a-=2* 32 | Math.PI/3,d=f*(1-b),g=f*(1+b*Math.cos(a)/Math.cos(Math.PI/3-a)),c=3*f-(g+d)):(a-=4*Math.PI/3,g=f*(1-b),c=f*(1+b*Math.cos(a)/Math.cos(Math.PI/3-a)),d=3*f-(g+c));return{R:d,G:g,B:c}},applyInHSI:function(a,b){for(var f=a.data,c=0,d=f.length;cg.S&&(g.S=0);g=this.HSIToRGB(g.H,g.S,g.I);f[c]=g.R;f[c+1]=g.G;f[c+2]=g.B}},applyInCoordinate:function(){},distance:function(a,b){b=b||[0,0];a=new c.C(a[0],a[1]);b=new c.C(b[0],b[1]);return a.minus(b).distance()}, 33 | xyToIFun:function(a){return function(b,c,i){return 4*(c*a+b)+(i||0)}},xyCal:function(a,b,c,i,d){for(var g=this.xyToIFun(a.width),j=0;3>j;j++){var m=g(b,c,j);a[m]=i(a[m])}d&&(a[m+1]=d(a[m+1]))}};c.Matrix.prototype={plus:function(a){if(this.m!=a.m||this.n!=a.n)throw Error("\u77e9\u9635\u52a0\u6cd5\u884c\u5217\u4e0d\u5339\u914d");for(var b=new c.Matrix([],this.m,this.n),f=0;fk&&m.push([f,h]);b=p.lib.dorsyMath.xyToIFun(d);f=0;for(d=parseInt(d/j);fg;g++)b[f+g]=c[d+g]-c[m+g]+127.5;b[f+4]=c[f+4]}}f=0;for(i=c.length;fm;m++){var k=parseInt(2*Math.random()*a)-a;b[4*j+m]+=k}return h}}})})("psLib"); 48 | (function(h){window[h].module("oilPainting",function(){return{process:function(h,c){for(var a=parseInt(c[0])||16,b=h.data,f=h.width,i=h.height,d=0;dk;k++)m+=b[4*j+k];m/=3;m=parseInt(m/a)*a;for(k=0;3>k;k++)b[4*j+k]=m}return h}}})})("psLib"); 49 | (function(h){window[h].module("setHSI",function(h){return{process:function(c,a){a[0]=a[0]/180*Math.PI;a[1]=a[1]/100||0;a[2]=255*(a[2]/100)||0;a[3]=a[3]||!1;h.lib.dorsyMath.applyInHSI(c,function(b){a[3]?(b.H=a[0],b.S=a[1]):(b.H+=a[0],b.S+=a[1]);b.I+=a[2]});return c}}})})("psLib"); 50 | (function(h){window[h].module("sharp",function(){return{process:function(h,c){for(var a=c[0]||0.6,b=h.data,f=h.width,i=0,d=b.length;im;m++)b[i+m]+=(b[i+m]-(b[j+m]+b[g+m]+b[k+m])/3)*a}return h}}})})("psLib"); 51 | (function(h){window[h].module("toGray",function(){return{process:function(h){for(var c=h.data,a=0,b=c.length;aa?255:0);c.data=b;return c}}})})("psLib"); 53 | -------------------------------------------------------------------------------- /nsrc/alloyimage.base.js: -------------------------------------------------------------------------------- 1 | /** 2 | * AlloyImage base module 3 | * Just Like AlloyImage, It's Powerful and Easily to use! 4 | * @author dorsywang From Tencent AlloyTeam 5 | */ 6 | 7 | //define the base module module: AlloyImage or $AI; 8 | AIDefine('AlloyImage', ['process', 'info', 'fix', 'util'], function(P, Info, Fix, Util){ 9 | 10 | var device = Util.getDevice(); 11 | 12 | var AlloyImage = function(img, width, height){ 13 | var _this = this; 14 | 15 | if(this instanceof AlloyImage){ 16 | //记录时间 time trace 17 | this.startTime = + new Date(); 18 | 19 | var canvas = document.createElement("canvas"); 20 | var context = canvas.getContext("2d"); 21 | 22 | //var l = psLib(20,30);构造适配 23 | if(!isNaN(img)){ 24 | 25 | canvas.width = img; 26 | canvas.height = width; 27 | height = height || "#fff"; 28 | context.fillStyle = height; 29 | context.fillRect(0, 0, img, width); 30 | 31 | this.srcImg = ""; 32 | 33 | }else if(typeof img == "string"){ 34 | var tmpImg = new Image(); 35 | tmpImg.onload = function(){ 36 | canvas.width = parseInt(this.width); 37 | canvas.height = parseInt(this.height); 38 | 39 | context.drawImage(this, 0, 0, this.width, this.height); 40 | }; 41 | tmpImg.src = img; 42 | }else{ 43 | var dw = width, dh = height; 44 | 45 | var sw = img.width, sh = img.height; 46 | var ratio = sw / sh; 47 | 48 | if(width || height){ 49 | if(! height){ 50 | dh = ~~ (dw / ratio); 51 | }else if(! width){ 52 | dw = dh * ratio; 53 | } 54 | }else{ 55 | dw = sw; 56 | dh = sh; 57 | } 58 | 59 | canvas.width = dw; 60 | canvas.height = dh; 61 | 62 | if(! isNaN(dw)){ 63 | if(device == "ios"){ 64 | Fix.drawImageIOS(context, img, dw, dh); 65 | }else{ 66 | context.drawImage(img, 0, 0, dw, dh); 67 | } 68 | 69 | }else context.drawImage(img, 0, 0); 70 | 71 | this.srcImg = img; 72 | 73 | } 74 | 75 | //将引用的canvas对象挂接到对象上 76 | this.canvas = canvas; 77 | this.context = context; 78 | this.imgData = context.getImageData(0, 0, canvas.width, canvas.height); 79 | 80 | //赋予对象唯一ID 81 | this.name = "AlloyImage_" + Math.random(); 82 | this.canvas.id = this.name; 83 | 84 | //记录挂接到图层上的对象的引用 85 | this.layers = []; 86 | 87 | //原生canvas支持时的临时canvas 88 | var ctxCanvas = document.createElement("canvas"); 89 | ctxCanvas.width = canvas.width; 90 | ctxCanvas.height = canvas.height; 91 | 92 | this.ctxCanvas = ctxCanvas; 93 | this.ctxContext = canvas.getContext("2d"); 94 | 95 | //设置对象的宽高 96 | this.width = this.canvas.width; 97 | this.height = this.canvas.height; 98 | 99 | //默认使用worker进行处理 100 | this.useWorker = P.useWorker; 101 | 102 | //初始化readyState为ready,readyState表明处理就绪 103 | this.readyState = 1; 104 | 105 | if(this.useWorker){ 106 | //如果使用worker,则初始化一个dorsyWorker封装实例出来 107 | this.dorsyWorker = P.lib.dorsyWorker(this); 108 | } 109 | 110 | //mix P.lib.Tools method to $AI.Tools 111 | if(P.lib.Tools){ 112 | for(var i in P.lib.Tools){ 113 | this.Tools[i] = (function(i){ 114 | return function(args){ 115 | return _this.Tools(i, args); 116 | }; 117 | })(i); 118 | } 119 | } 120 | 121 | }else{ 122 | 123 | //返回自身构造对象 124 | return new AlloyImage(img, width, height); 125 | } 126 | }; 127 | 128 | //原型对象 129 | window[Ps].prototype = { 130 | set width(w){ 131 | this.canvas.width = w; 132 | }, 133 | 134 | set height(h){ 135 | this.canvas.height = h; 136 | }, 137 | 138 | get width(){ 139 | return this.canvas.width; 140 | }, 141 | 142 | get height(){ 143 | return this.canvas.height; 144 | }, 145 | 146 | //动作 147 | act: function(method, arg){ 148 | //console.log("actStart"); 149 | var args = []; 150 | 151 | //提取参数为数组 152 | args = Array.prototype.slice.call(arguments, 1); 153 | 154 | if(this.useWorker){ 155 | this.dorsyWorker.queue.push(["act", method, args]); 156 | 157 | checkStartWorker.call(this); 158 | 159 | }else{ 160 | //做一次转发映射 161 | P.reflect(method, this.imgData, args); 162 | 163 | } 164 | 165 | return this; 166 | }, 167 | 168 | //预览模式 ,所有的再操作全部基于原点,不会改变本图层的效果,直到act会去除这部分图层 169 | view: function(method, arg1, arg2, arg3, arg4){ 170 | 171 | //克隆本图层对象 172 | var newLayer = this.clone(); 173 | 174 | //标记本图层的种类为预览的已合并的图层 175 | newLayer.type = 1; 176 | 177 | //挂接克隆图层副本到对象 178 | this.addLayer(newLayer, "正常", 0, 0); 179 | newLayer.act(method, arg1, arg2, arg3, arg4); 180 | 181 | return this; 182 | }, 183 | 184 | //将view的结果执行到图层 185 | excute: function(){ 186 | var layers = this.layers; 187 | var n = layers.length; 188 | if(layers[n - 1] && layers[n - 1][0].type == 1){ 189 | this.imgData = layers[n - 1][0].imgData; 190 | delete layers[n - 1]; 191 | } 192 | }, 193 | 194 | //取消view的结果执行 195 | cancel: function(){ 196 | var layers = this.layers; 197 | var n = layers.length; 198 | if(layers[n - 1] && layers[n - 1][0].type == 1){ 199 | delete layers[n - 1]; 200 | } 201 | }, 202 | 203 | //显示对象 isFast用于快速显示 204 | show: function(selector, isFast, flag){ 205 | 206 | if(flag){ 207 | }else{ 208 | if(this.useWorker){ 209 | this.dorsyWorker.queue.push(["show", selector, isFast]); 210 | return this; 211 | } 212 | } 213 | 214 | //如果其上无其他挂载图层,加快处理 215 | if(this.layers.length == 0){ 216 | this.tempPsLib = { 217 | imgData: this.imgData 218 | }; 219 | }else{ 220 | 221 | //创建一个临时的psLib对象,防止因为合并显示对本身imgData影响 222 | var tempPsLib = new window[Ps](this.canvas.width, this.canvas.height); 223 | tempPsLib.add(this, "正常", 0, 0, isFast); 224 | this.tempPsLib = tempPsLib; 225 | 226 | //将挂接到本对象上的图层对象 一起合并到临时的psLib对象上去 用于显示合并的结果,不会影响每个图层,包括本图层 227 | for(var i = 0; i < this.layers.length; i ++){ 228 | var tA = this.layers[i]; 229 | var layers = tA[0].layers; 230 | var currLayer = tA[0]; 231 | 232 | if(layers[layers.length - 1] && layers[layers.length - 1][0].type == 1) currLayer = layers[layers.length - 1][0]; 233 | tempPsLib.add(currLayer, tA[1], tA[2], tA[3], isFast); 234 | } 235 | 236 | this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 237 | 238 | } 239 | 240 | //以临时对象data显示 241 | this.context.putImageData(this.tempPsLib.imgData, 0, 0); 242 | 243 | if(selector){ 244 | if(typeof selector == "string"){ 245 | var el = document.querySelector(selector); 246 | el.appendChild(this.canvas); 247 | }else{ 248 | selector.appendChild(this.canvas); 249 | } 250 | }else{ 251 | document.body.appendChild(this.canvas); 252 | } 253 | 254 | return this; 255 | }, 256 | 257 | //替换到某元素里 258 | replaceChild: function(selector){ 259 | var el; 260 | if(typeof selector == "string"){ 261 | el = document.querySelector(selector); 262 | }else{ 263 | el = selector; 264 | } 265 | 266 | el.innerHTML = ""; 267 | return this.show(el); 268 | }, 269 | 270 | //替换原来的图片 271 | replace: function(img, workerFlag){ 272 | if(workerFlag){ 273 | }else{ 274 | if(this.useWorker){ 275 | this.dorsyWorker.queue.push(['replace', img]); 276 | checkStartWorker.call(this); 277 | 278 | return this; 279 | } 280 | } 281 | 282 | if(img){ 283 | img.onload = function(){}; 284 | img.src = this.save(0, 1, workerFlag); 285 | } 286 | 287 | return this; 288 | }, 289 | 290 | //合并一个AlloyImage图层上去 291 | add: function(){ 292 | 293 | var numberArr = [], psLibObj, method, alpha, dx, dy, isFast, channel; 294 | 295 | //做重载 296 | for(var i = 0; i < arguments.length; i ++){ 297 | if(!i) continue; 298 | 299 | switch(typeof(arguments[i])){ 300 | case "string": 301 | if(/\d+%/.test(arguments[i])){//alpha 302 | alpha = arguments[i].replace("%", ""); 303 | }else if(/[RGB]+/.test(arguments[i])){//channel 304 | channel = arguments[i]; 305 | }else{//method 306 | method = arguments[i]; 307 | } 308 | break; 309 | 310 | case "number": 311 | numberArr.push(arguments[i]); 312 | break; 313 | 314 | case "boolean": 315 | isFast = arguments[i]; 316 | break; 317 | } 318 | } 319 | 320 | //赋值 321 | dx = numberArr[0] || 0; 322 | dy = numberArr[1] || 0; 323 | method = method || "正常"; 324 | alpha = alpha / 100 || 1; 325 | isFast = isFast || false; 326 | channel = channel || "RGB"; 327 | 328 | psLibObj = arguments[0]; 329 | 330 | //console.log("add init"); 331 | 332 | if(this.useWorker){ 333 | this.dorsyWorker.queue.push(['add', psLibObj, method, alpha, dx, dy, isFast, channel]); 334 | 335 | checkStartWorker.call(this); 336 | 337 | }else{ 338 | //做映射转发 339 | P.add(this.imgData, psLibObj.imgData, method, alpha, dx, dy, isFast, channel); 340 | } 341 | 342 | return this; 343 | }, 344 | 345 | //挂载一个图层上去,不会影响本身,只是显示有变化 346 | addLayer: function(psLibObj, method, dx, dy){ 347 | this.layers.push([psLibObj, method, dx, dy]); 348 | 349 | return this; 350 | }, 351 | 352 | clone: function(workerFlag){ 353 | 354 | /* 355 | if(workerFlag){ 356 | }else{ 357 | 358 | if(this.useWorker){ 359 | this.dorsyWorker.queue.push(['clone']); 360 | return this; 361 | } 362 | } 363 | */ 364 | 365 | var tempPsLib = new window[Ps](this.canvas.width, this.canvas.height); 366 | tempPsLib.context.putImageData(this.imgData, 0, 0); 367 | tempPsLib.imgData = tempPsLib.context.getImageData(0, 0, this.canvas.width, this.canvas.height); 368 | /* 369 | tempPsLib.add(this); 370 | */ 371 | 372 | return tempPsLib; 373 | }, 374 | 375 | //交换a,b图层的顺序,ab代表当前序号 376 | swap: function(a, b){ 377 | var temp = this.layers[a]; 378 | this.layers[a] = this.layers[b]; 379 | this.layers[b] = temp; 380 | 381 | return this; 382 | }, 383 | 384 | //删除几个图层序号 385 | deleteLayers: function(arr){ 386 | this.layers = this.layers.del(arr); 387 | }, 388 | 389 | //返回一个合成后的图像 png base64 390 | //comRatio为压缩质量 391 | save: function(type, comRatio, workerFlag){ 392 | type = type || "png"; 393 | type = type.toLowerCase(); 394 | 395 | comRatio = comRatio || 0.8; 396 | 397 | if(type == "jpg") type = "jpeg"; 398 | 399 | var mimeType = "image/" + type; 400 | 401 | if(workerFlag){ 402 | }else{ 403 | if(this.useWorker){ 404 | this.dorsyWorker.queue.push(['save']); 405 | checkStartWorker.call(this); 406 | 407 | return this; 408 | } 409 | } 410 | 411 | //如果没有挂接图片 直接返回 412 | if(! this.layers.length){ 413 | this.context.putImageData(this.imgData, 0, 0); 414 | return this.canvas.toDataURL(mimeType, comRatio); 415 | } 416 | 417 | 418 | //创建一个临时的psLib对象,防止因为合并显示对本身imgData影响 419 | var tempPsLib = new window[Ps](this.canvas.width, this.canvas.height); 420 | tempPsLib.add(this, "正常", 0, 0, isFast); 421 | this.tempPsLib = tempPsLib; 422 | 423 | //将挂接到本对象上的图层对象 一起合并到临时的psLib对象上去 用于显示合并的结果,不会影响每个图层,包括本图层 424 | for(var i = 0; i < this.layers.length; i ++){ 425 | var tA = this.layers[i]; 426 | var layers = tA[0].layers; 427 | var currLayer = tA[0]; 428 | 429 | if(layers[layers.length - 1] && layers[layers.length - 1][0].type == 1) currLayer = layers[layers.length - 1][0]; 430 | 431 | tempPsLib.add(currLayer, tA[1], tA[2], tA[3], isFast); 432 | } 433 | 434 | this.context.clearRect(0, 0, this.canvas.width, this.canvas.height); 435 | 436 | //以临时对象data显示 437 | this.context.putImageData(tempPsLib.imgData, 0, 0); 438 | 439 | return this.canvas.toDataURL(mimeType, comRatio); 440 | }, 441 | 442 | //下载图片 443 | saveFile: function(fileName, comRatio){ 444 | fileName = fileName || "AlloyImage合成图像.jpg"; 445 | comRatio = comRatio || 1; 446 | 447 | var formatReg = /.*.(jpg|png|gif|jpeg)$/g; 448 | var format = "png"; 449 | 450 | if(formatReg.test(fileName)){ 451 | formatReg.lastIndex = 0; 452 | format = formatReg.exec(fileName)[1]; 453 | }else{ 454 | fileName += ".png"; 455 | } 456 | 457 | var fileData = this.save(format, comRatio); 458 | 459 | var a = document.createElement('a'); 460 | a.href = fileData; 461 | a.download = fileName; 462 | 463 | var e = document.createEvent("HTMLEvents"); 464 | e.initEvent("click", false, false); 465 | 466 | a.dispatchEvent(e); 467 | 468 | }, 469 | 470 | download: function(fileName, comRatio){ 471 | this.saveFile(fileName, comRatio); 472 | }, 473 | 474 | saveAsDataURL: function(){ 475 | }, 476 | 477 | saveAsBlob: function(){ 478 | }, 479 | 480 | saveAsBuffer: function(){ 481 | }, 482 | 483 | //绘制直方图 484 | drawRect: function(selector){ 485 | var canvas; 486 | 487 | if(canvas = document.getElementById("imgRect")){ 488 | }else{ 489 | canvas = document.createElement("canvas"); 490 | canvas.id = "imgRect"; 491 | document.body.appendChild(canvas); 492 | canvas.width = parseInt(this.canvas.width); 493 | canvas.height = parseInt(this.canvas.height); 494 | } 495 | 496 | var context = canvas.getContext("2d"); 497 | context.clearRect(0, 0, canvas.width, canvas.height); 498 | 499 | var result = []; 500 | var data = this.tempPsLib.imgData.data; 501 | 502 | for(var i = 0, n = data.length; i < n; i ++){ 503 | if(!result[data[i]]){ 504 | result[data[i]] = 1; 505 | }else{ 506 | result[data[i]] ++; 507 | } 508 | } 509 | 510 | context.beginPath(); 511 | context.moveTo(0, canvas.height); 512 | 513 | var max = 0; 514 | 515 | for(var i = 0; i < 255; i ++){ 516 | if(result[i] > max) max = result[i]; 517 | } 518 | 519 | for(var i = 0; i < 255; i ++){ 520 | var currY = result[i] || 0; 521 | currY = canvas.height - currY / max * 0.8 * canvas.height; 522 | context.lineTo(i / 256 * canvas.width, currY, 1, 1); 523 | } 524 | 525 | context.lineTo(canvas.width + 10, canvas.height); 526 | context.fill(); 527 | }, 528 | 529 | //组合效果 530 | ps: function(effect){ 531 | if(effect == "原图" || effect == "origin" || effect == ""){ 532 | return this; 533 | } 534 | 535 | var fun = P.reflectEasy(effect); 536 | var psedPic = fun.call(this, this.canvas); 537 | 538 | //this.logTime("组合效果" + effect); 539 | 540 | return psedPic; 541 | }, 542 | 543 | //记录运行时间 544 | logTime: function(msg){ 545 | //console.log(msg + ": " + (+ new Date() - this.startTime) / 1000 + "s"); 546 | }, 547 | 548 | //调用原生canvas.context接口 549 | ctx: function(func){ 550 | //func中的this指向context 551 | var ctx = this.ctxContext; 552 | 553 | ctx.putImageData(this.imgData, 0, 0); 554 | 555 | //调用func 556 | func.call(ctx); 557 | this.imgData = ctx.getImageData(0, 0, this.canvas.width, this.canvas.height); 558 | 559 | return this; 560 | }, 561 | 562 | notify: function(msg){ 563 | //通知 564 | if(msg == "readyStateOK") this.readyState = 1; 565 | }, 566 | 567 | //所有动作异步执行完了的回调 568 | complete: function(func){ 569 | if(this.useWorker){ 570 | //console.log("complete init"); 571 | this.dorsyWorker.queue.push(['complete', func]); 572 | }else{ 573 | func(); 574 | } 575 | }, 576 | 577 | //变换Matrix 578 | //x0, y0坐标原点 579 | transform: function(matrix, x0, y0){ 580 | //获取dorsyMath接口 581 | var dM = window[Ps].dorsyMath(); 582 | 583 | var ctx = this.ctxContext; 584 | ctx.putImageData(this.imgData, 0, 0); 585 | 586 | //建立一个空的临时canvas 587 | var tempCtx = document.createElement("canvas").getContext("2d"); 588 | 589 | //计算变换后的canvas宽度 590 | //原则 所有的变换不会记录平移带来的变的换,但会记录下平移导致的原点的平移,以叠加图层的时候减去这些平移造成的影响 591 | //意味着图层自身所有的变换都不会丢失自己的图像信息 但会原点位置发生变化 592 | //这样做会节省很大的无图像空间 593 | 594 | //计算原有点变换后的点 595 | var originPoint = [ 596 | new dM.Matrix([0, 0], "1*2"), 597 | new dM.Matrix([0, this.canvas.height], "1*2"), 598 | new dM.Matrix([this.canvas.width, 0], "1 * 2"), 599 | new dM.Matrix([this.canvas.width, this.canvas.height], "1*2") 600 | ]; 601 | 602 | var transformedPoint = []; 603 | var transformMatrix = new dM.Matrix(matrix, "2*2"); 604 | 605 | for(var i = 0; i < originPoint.length; i ++){ 606 | transformedPoint.push(originPoint[i].mutiply(transformMatrix)); 607 | } 608 | 609 | var maxX = Math.max( 610 | transformedPoint[0].data[0][0], 611 | transformedPoint[1].data[0][0], 612 | transformedPoint[2].data[0][0], 613 | transformedPoint[3].data[0][0] 614 | ); 615 | 616 | var minX = Math.min( 617 | transformedPoint[0].data[0][0], 618 | transformedPoint[1].data[0][0], 619 | transformedPoint[2].data[0][0], 620 | transformedPoint[3].data[0][0] 621 | ); 622 | 623 | var maxY = Math.max( 624 | transformedPoint[0].data[0][1], 625 | transformedPoint[1].data[0][1], 626 | transformedPoint[2].data[0][1], 627 | transformedPoint[3].data[0][1] 628 | ); 629 | 630 | var minY = Math.min( 631 | transformedPoint[0].data[0][1], 632 | transformedPoint[1].data[0][1], 633 | transformedPoint[2].data[0][1], 634 | transformedPoint[3].data[0][1] 635 | ); 636 | 637 | var width = ~~ (maxX - minX); 638 | var height = ~~ (maxY - minY); 639 | 640 | tempCtx.canvas.width = width; 641 | tempCtx.canvas.height = height; 642 | 643 | //将原点平移使图像显示出来 但图像的原点会发生变化 644 | tempCtx.translate(- minX, - minY); 645 | tempCtx.transform.apply(tempCtx, matrix); 646 | tempCtx.drawImage(ctx.canvas, 0, 0); 647 | 648 | this.canvas.width = width; 649 | this.canvas.height = height; 650 | 651 | this.width = width; 652 | this.height = height; 653 | 654 | this.imgData = tempCtx.getImageData(0, 0, width, height); 655 | 656 | return this; 657 | }, 658 | 659 | scale: function(x, y){ 660 | var y = y || x; 661 | return this.transform([x, 0, 0, y, 0, 0]); 662 | }, 663 | 664 | //缩放到宽度和高度 665 | scaleTo: function(w, h){ 666 | var _this = this; 667 | var width = this.width; 668 | var height = this.height; 669 | 670 | var scaleSizeX, scaleSizeY; 671 | 672 | if(! h){ 673 | h = w * height / width; 674 | } 675 | 676 | if(! w){ 677 | w = h * (width / height); 678 | } 679 | 680 | //这里的代码在iphone上会导致倾斜 681 | if(0 && this.srcImg){ 682 | var img = new Image(); 683 | img.width = w; 684 | img.height = h; 685 | 686 | document.body.appendChild(img); 687 | 688 | img.style.width = w + "px"; 689 | img.style.height = ~~ h + "px"; 690 | 691 | img.src = this.srcImg.src; 692 | 693 | 694 | var newAIObj = window[Ps](img, w, h); 695 | 696 | document.body.removeChild(img); 697 | img = null; 698 | 699 | setTimeout(function(){ 700 | if(_this.canvas.parentNode){ 701 | _this.canvas.parentNode.replaceChild(newAIObj.canvas, _this.canvas); 702 | newAIObj.show(); 703 | } 704 | }, 10); 705 | 706 | return newAIObj; 707 | 708 | }else{ 709 | 710 | if(w && h){ 711 | scaleSizeX = w / width; 712 | scaleSizeY = h / height; 713 | 714 | return this.scale(scaleSizeX, scaleSizeY); 715 | } 716 | } 717 | }, 718 | 719 | //旋转 度 720 | rotate: function(deg){ 721 | //转为弧度 722 | var r = deg / 180 * Math.PI; 723 | var matrix = [ 724 | Math.cos(r), Math.sin(r), -Math.sin(r), Math.cos(r), 0, 0 725 | ]; 726 | 727 | return this.transform(matrix); 728 | }, 729 | 730 | //平移 731 | moveTo: function(x, y){ 732 | x = x || 0; 733 | y = y || 0; 734 | 735 | return this.transform([1, 0, 0, 1, x, y]); 736 | }, 737 | 738 | //裁切 739 | clip: function(sx, sy, w, h){ 740 | // @todo 多图层挂接支持 741 | 742 | //将图像信息放置于临时canvas上 743 | this.ctxContext.putImageData(this.imgData, 0, 0); 744 | 745 | //取到相关矩阵的图像信息 746 | this.imgData = this.ctxContext.getImageData(sx, sy, w, h); 747 | 748 | this.context.canvas.width = w; 749 | this.context.canvas.height = h; 750 | 751 | return this; 752 | }, 753 | 754 | //图像的工具方法 不会返回AI本身 755 | Tools: function(args){ 756 | return P.tools(this.imgData, arguments); 757 | } 758 | }; 759 | 760 | //out put APIs of AlloyImage; 761 | AIExport.external('AlloyImage', AlloyImage); 762 | AIExport.external('$AI', AlloyImage); 763 | }); 764 | --------------------------------------------------------------------------------