Przeglądaj źródła

增加页面取色工具

Alien 9 lat temu
rodzic
commit
61d53a386f

+ 6 - 1
chrome/manifest.json

@@ -5,7 +5,7 @@
 
     "default_locale": "zh_CN",
 
-    "description": "FE助手:包括字符串编解码、代码压缩、美化、JSON格式化、正则表达式、时间转换工具、二维码生成器、编码规范检测、页面性能检测、栅格检测等",
+    "description": "FE助手:包括字符串编解码、代码压缩、美化、JSON格式化、正则表达式、时间转换工具、二维码生成器、编码规范检测、页面性能检测、页面取色等",
     "icons": {
         "16": "static/img/fe-16.png",
         "48": "static/img/fe-48.png",
@@ -46,6 +46,8 @@
         "static/img/fe-128.png",
         "static/img/pbar-ani.gif",
         "static/img/ui-icons_228ef1_256x240.png",
+        "static/img/crosshair.png",
+        "static/img/close.png",
         "static/css/fe-helper.css",
         "static/css/fe-jsonformat-content.css",
         "static/vendor/jquery-ui-1.8/css/jquery-ui-1.8.16.custom.hot_datauri.css"
@@ -79,6 +81,9 @@
                 "static/js/fe-helper.js",
                 "static/js/wpo/fe-calc-wpo.js",
 
+                "static/js/colorpicker/elem-tool.js",
+                "static/js/colorpicker/colorpicker.js",
+
                 "static/js/jsonformat/json-format-dealer.js",
                 "static/js/jsonformat/json-format-ent.js",
                 "static/js/jsonformat/contentscript-jsonformat.js"

+ 3 - 1
chrome/online.manifest.json

@@ -5,7 +5,7 @@
 
     "default_locale": "zh_CN",
 
-    "description": "FeHelper:包括字符串编解码、图片base64编码、代码压缩、美化、JSON格式化、正则表达式、时间转换工具、二维码生成器、编码规范检测、页面性能检测、JS运行效率分析等",
+    "description": "FE助手:包括字符串编解码、代码压缩、美化、JSON格式化、正则表达式、时间转换工具、二维码生成器、编码规范检测、页面性能检测、页面取色等",
     "icons": {
         "16": "static/img/fe-16.png",
         "48": "static/img/fe-48.png",
@@ -46,6 +46,8 @@
         "static/img/fe-128.png",
         "static/img/pbar-ani.gif",
         "static/img/ui-icons_228ef1_256x240.png",
+        "static/img/crosshair.png",
+        "static/img/close.png",
         "static/css/fe-helper.css",
         "static/css/fe-jsonformat-content.css",
         "static/vendor/jquery-ui-1.8/css/jquery-ui-1.8.16.custom.hot_datauri.css"

+ 3 - 0
chrome/static/css/fe-popup.css

@@ -82,6 +82,9 @@ ul.fe-function-list li.-x-codecompress b {
 ul.fe-function-list li.-x-base64 b {
     background-position:-33px -209px;
 }
+ul.fe-function-list li.-x-colorpicker b {
+    background-position:-64px -112px;
+}
 .fe-feedback {
 	font-size:12px;
 	border-top:1px dotted #ddd;

BIN
chrome/static/img/close.png


BIN
chrome/static/img/colorpicker.png


BIN
chrome/static/img/crosshair.png


+ 650 - 0
chrome/static/js/colorpicker/colorpicker.js

@@ -0,0 +1,650 @@
+var FeHelper = window.FeHelper || {};
+
+/**
+ * 页面取色器
+ */
+FeHelper.ColorPicker = (function () {
+
+    var elmid1 = 'fehelper-colorpicker-box', elmid2 = 'fehelper-colorpicker-result';
+    var popupsShowing = 0;
+
+    function _ge(n) {
+        return document.getElementById(n);
+    }
+
+    var n = false, c = false, hex = 'F00BAF', lasthex = '', rgb = null;
+    var hsv = null;
+    var ex = 0, ey = 0, isEnabled = false, isLocked = false, hexIsLowerCase = false, borderValue = '1px solid #666', blankgif = '';
+    var isUpdating = false, lastTimeout = 0, lx = 0, ly = 0;
+    var cvs = document.createElement('canvas');
+    var ctx = cvs.getContext('2d'), x_cvs_scale = 1, y_cvs_scale = 1;
+
+    function RGBtoHex(R, G, B) {
+        return applyHexCase(toHex(R) + toHex(G) + toHex(B))
+    }
+
+    function applyHexCase(hex) {
+        return hexIsLowerCase ? hex.toLowerCase() : hex;
+    }
+
+    function toHex(N) {//http://www.javascripter.net/faq/rgbtohex.htm
+        if (N == null) return "00";
+        N = parseInt(N);
+        if (N == 0 || isNaN(N)) return "00";
+        N = Math.max(0, N);
+        N = Math.min(N, 255);
+        N = Math.round(N);
+        return "0123456789ABCDEF".charAt((N - N % 16) / 16) + "0123456789ABCDEF".charAt(N % 16);
+    }
+
+    function rgb2hsl(r, g, b) {//http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript
+        r /= 255, g /= 255, b /= 255;
+        var max = Math.max(r, g, b), min = Math.min(r, g, b);
+        var h, s, l = (max + min) / 2;
+        if (max == min) {
+            h = s = 0; // achromatic
+        } else {
+            var d = max - min;
+            s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
+            switch (max) {
+                case r:
+                    h = (g - b) / d + (g < b ? 6 : 0);
+                    break;
+                case g:
+                    h = (b - r) / d + 2;
+                    break;
+                case b:
+                    h = (r - g) / d + 4;
+                    break;
+            }
+            h /= 6;
+        }
+        return {
+            h: Math.round(h * 360),
+            s: Math.round(s * 100),
+            v: Math.round(l * 100)
+        };
+    }
+
+    function emptyNode(node) {
+        while (node.lastChild)node.removeChild(node.lastChild);
+    }
+
+    function snapshotLoaded() {
+        c.style.height = 'auto';
+        c.style.width = (innerWidth) + 'px';
+        x_cvs_scale = c.naturalWidth / innerWidth;
+        y_cvs_scale = c.naturalHeight / innerHeight;
+        cvs.width = c.naturalWidth;
+        cvs.height = c.naturalHeight;
+        ctx.drawImage(c, 0, 0);
+
+        setTimeout(function () {
+            isMakingNew = false;
+            c.style.visibility = "visible";
+            n.style.visibility = "visible";
+            document.body.style.cursor = 'url(' + chrome.extension.getURL('static/img/crosshair.png') + ') 16 16,crosshair';
+            updateColorPreview();
+        }, 255);
+    }
+
+
+    function setPixelPreview(pix, hxe, lhex) {
+        if (isLocked)return;
+        var wid = 75, padr = 32;
+        wid = 150;
+        hex = hxe ? hxe : hex;
+        if (!_ge('fehelper-colorpicker-cpimprev') || (rgb && !_ge('cprgbvl'))) {
+            emptyNode(n);
+            FeHelper.elemTool.elm('div', {}, [
+                FeHelper.elemTool.elm('img', {
+                    id: 'fehelper-colorpicker-cpimprev',
+                    height: wid,
+                    width: wid,
+                    src: pix,
+                    style: 'margin:0px;padding:0px;margin:0px;'
+                }),
+                FeHelper.elemTool.elm('br'),
+                FeHelper.elemTool.elm('input', {
+                    type: 'text',
+                    size: 7,
+                    style: 'width:60px;height:20px;line-height:20px;font-size:10pt;border:' + borderValue,
+                    id: 'fehelper-colorpicker-cphexvl',
+                    value: '#' + hex,
+                    event: ['mouseover', selectTargElm]
+                })
+            ], n)
+            keepOnScreen();
+        } else {
+            _ge('fehelper-colorpicker-cpimprev').src = pix;
+            _ge('fehelper-colorpicker-cpimprev').width = wid;
+            _ge('fehelper-colorpicker-cpimprev').height = wid;
+            _ge('fehelper-colorpicker-cphexvl').value = hex;
+            n.style.backgroundColor = '#' + hex;
+        }
+    }
+
+    function setCurColor(r) {
+        if (!n)return;
+        hex = r.hex ? r.hex : hex;
+        n.style.backgroundColor = '#' + hex;
+        if (isLocked)setDisplay();
+    }
+
+    function selectTargElm(ev) {
+        ev.target.select();
+    }
+
+    function setDisplay() {//FeHelper.elemTool.elm
+        emptyNode(n);
+        FeHelper.elemTool.elm('div', {}, [
+            FeHelper.elemTool.elm('input', {
+                type: 'text',
+                size: 7,
+                style: 'width:80px;height:20px;line-height:20px;font-size:10pt;border:' + borderValue,
+                id: 'fehelper-colorpicker-cphexvl',
+                value: '#' + hex,
+                event: ['mouseover', selectTargElm]
+            }),
+            FeHelper.elemTool.elm('img', {
+                style: 'width:20px;height:20px;position:absolute;top:-10px;right:-10px;cursor:pointer;',
+                src: chrome.extension.getURL('static/img/close.png'),
+                alt: 'Close',
+                title: '[esc]键可直接关闭',
+                id: 'fehelper-colorpicker-exitbtn',
+                event: ['click', dissableColorPickerFromHere, true]
+            })
+        ], n);
+        if (_ge('fehelper-colorpicker-cphexvl'))_ge('fehelper-colorpicker-cphexvl').select();
+        keepOnScreen();
+    }
+
+    function picked() {
+        if (isLocked) {
+            lasthex = hex;
+            isLocked = false;
+            emptyNode(n);
+        } else {
+            isLocked = true;
+            setDisplay();
+        }
+    }
+
+    function dissableColorPickerFromHere() {
+        var disableTimeout = setTimeout(disableColorPicker, 500)
+        chrome.runtime.sendMessage({disableColorPicker: true}, function (r) {
+            clearTimeout(disableTimeout);
+        });
+    }
+
+    function disableColorPicker() {
+        isEnabled = false, isLocked = false;
+        document.removeEventListener('mousemove', mmf);
+        removeEventListener('scroll', ssf);
+        removeEventListener('resize', ssf);
+        removeEventListener('keyup', wk);
+        removeExistingNodes();
+        clearTimeout(lastNewTimeout);
+    }
+
+    function removeExistingNodes() {
+        if (document.body) {
+            c = _ge(elmid1), n = _ge(elmid2);
+            if (c)document.body.removeChild(c);
+            if (n)document.body.removeChild(n);
+            c = false, n = false;
+            document.body.style.cursor = 'default';
+        }
+    }
+
+    function wk(ev) {
+        if (!isEnabled)return;
+        if (ev.keyCode == 27) {
+            dissableColorPickerFromHere();
+        } else if (ev.keyCode == 82 || ev.keyCode == 74) {//r or j refresh
+            ssf();
+        } else if (ev.keyCode == 13) {
+            picked();
+        }
+    }
+
+    function mmf(ev) {
+        if (!isEnabled)return;
+        if (!isLocked) {
+            lx = (ev.pageX - pageXOffset), ly = (ev.pageY - pageYOffset);
+            ex = Math.round(lx * x_cvs_scale),
+                ey = Math.round(ly * y_cvs_scale);
+            updateColorPreview();
+        }
+    }
+
+    function ssf(ev) {
+        if (!isEnabled)return;
+        n.style.visibility = "hidden";
+        c.style.visibility = "hidden";//redundent?
+        clearTimeout(lastNewTimeout);
+        lastNewTimeout = setTimeout(function () {
+            newImage()//some delay required OR it won't update
+        }, 250);
+    }
+
+    function initialInit() {
+        removeExistingNodes();
+        c = FeHelper.elemTool.elm('img', {
+            id: elmid1,
+            src: blankgif,
+            style: 'position:fixed;max-width:none!important;max-height:none!important;top:0px;left:0px;margin:0px;padding:0px;overflow:hidden;z-index:2147483646;',
+            events: [['click', picked, true], ['load', snapshotLoaded]]
+        }, [], document.body);
+        n = FeHelper.elemTool.elm('div', {
+            id: elmid2,
+            style: 'position:fixed;min-width:30px;max-width:300px;box-shadow:2px 2px 2px #666;border:' + borderValue + ';border-radius:5px;z-index:2147483646;cursor:default;padding:10px;text-align:center;'
+        }, [], document.body);
+        document.addEventListener('mousemove', mmf);
+        addEventListener('keyup', wk);
+        addEventListener('scroll', ssf);
+        addEventListener('resize', ssf);
+        testWebGlAvail();
+        initializeCanvas();
+        remainingInit();
+    }
+
+    function enableColorPicker() {
+        if (!n) {
+            initialInit();
+            return false;
+        }
+        return remainingInit();
+    }
+
+    function remainingInit() {
+        if (!isEnabled) {
+            n.style.visibility = "hidden";
+            c.style.visibility = "hidden";
+            if (isLocked)picked();//unlocks for next pick
+            document.body.style.cursor = 'url(' + chrome.extension.getURL('static/img/crosshair.png') + ') 16 16,crosshair';
+            isEnabled = true;
+            setTimeout(newImage, 1);
+            return false;
+        }
+        return true;
+    }
+
+    function keepOnScreen() {
+
+        if (!n)return;
+        n.style.top = (ly + 8) + "px";
+        n.style.left = (lx + 8) + "px";
+        if (n.clientWidth + n.offsetLeft + 24 > innerWidth) {
+            n.style.left = (lx - 8 - n.clientWidth) + "px";
+        }
+        if (n.clientHeight + n.offsetTop + 24 > innerHeight) {
+            n.style.top = (ly - 8 - n.clientHeight) + "px";
+        }
+    }
+
+    function updateColorPreview(ev) {
+        if (!isEnabled)return;
+        keepOnScreen();
+        var data = ctx.getImageData(ex, ey, 1, 1).data;
+        hsv = rgb2hsl(data[0], data[1], data[2]);
+        rgb = {r: data[0], g: data[1], b: data[2]};
+        setCurColor({hex: RGBtoHex(data[0], data[1], data[2])});
+        handleRendering();
+    }
+
+    var isMakingNew = false, lastNewTimeout = 0;
+
+    function newImage() {
+        if (!isEnabled)return;
+        if (isMakingNew) {
+            clearTimeout(lastNewTimeout);
+            lastNewTimeout = setTimeout(function () {
+                newImage()
+            }, 255);
+            return;
+        }
+        document.body.style.cursor = 'wait';
+        isMakingNew = true;
+        n.style.visibility = "hidden";
+        c.style.visibility = "hidden";
+        c.src = blankgif;
+        var x = innerWidth, y = innerHeight;
+        c.style.width = x + 'px';
+        c.style.height = y + 'px';
+
+        setTimeout(function () {
+            try {
+                chrome.runtime.sendMessage({type: 'color-picker:newImage'}, function (response) {
+                });
+            } catch (e) {
+                exitAndDetach();
+            }
+        }, 255);
+    }
+
+    var lastPreviewURI;
+    var gl = 0, texture = 0, texturectx = 0, snapTexture = 0, shaderProgram = 0, textureSampPosition = 0, fishEyeScalePosition = 0;
+
+    var webGlAvail = false, icvs = 0, totalWidth = 150;//750
+    function testWebGlAvail() {
+        var testc = document.createElement("canvas");
+        var testctx = testc.getContext('webgl');
+        if (testctx && typeof(testctx.getParameter) == "function") webGlAvail = true;
+        else webGlAvail = false;
+    }
+
+    function handleRendering(quick) {
+        var x = ex, y = ey;
+        if (isMakingNew) {
+            isUpdating = false;
+            return;
+        }
+
+        var startPoint = Math.floor(totalWidth * 0.5);
+        var ox = Math.round(x), oy = Math.round(y);
+
+        if (quick) {
+            var ictx = getMain2dContext();
+            ictx.scale(2, 2);
+            ictx.drawImage(cvs, -ox + (startPoint * 0.5), -oy + (startPoint * 0.5));
+            ictx.scale(0.5, 0.5);
+
+            ictx.fillStyle = "rgba(0,0,0,0.3)";//croshair
+            //ictx.globalAlpha = 1.0;
+
+            ictx.fillRect(startPoint, 0, 1, totalWidth);
+            ictx.fillRect(0, startPoint, totalWidth, 1);
+
+        } else {
+            if (webGlAvail) {
+                getMain3dContext();
+                texturectx.drawImage(cvs, -ox + (64), -oy + (64));
+                //gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture);
+                gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, 0, gl.RGBA, gl.UNSIGNED_BYTE, texture);
+                gl.uniform1i(textureSampPosition, 0);
+                gl.uniform1f(fishEyeScalePosition, 15)
+                gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
+            } else {
+                var ictx = getMain2dContext();
+                ictx.drawImage(cvs, -ox + (startPoint), -oy + (startPoint));
+                var smi, spi, mp = 15 - 0;
+                //xx,yy
+                for (var i = 0; i < startPoint; i += 2) {
+                    smi = startPoint - i;
+                    spi = startPoint + i;
+                    //drawImage(image, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight) //CANVAS
+                    ictx.drawImage(icvs, spi, 0, smi, totalWidth,//total width really??
+                        spi + 1, 0, smi, totalWidth);
+
+                    ictx.drawImage(icvs, 0, 0, smi + 1, totalWidth,
+                        -1, 0, smi + 1, totalWidth);
+
+                    ictx.drawImage(icvs, 0, spi, totalWidth, smi,
+                        0, spi + 1, totalWidth, smi);
+
+                    ictx.drawImage(icvs, 0, 0, totalWidth, smi + 1,
+                        0, -1, totalWidth, smi + 1);
+
+                    if (i == 0) {
+                        var dat = ictx.getImageData(startPoint, startPoint, 1, 1).data;//notarget
+                        var d = dat[0] + dat[1] + dat[2];
+                        if (d > 192) ictx.fillStyle = "rgba(30,30,30,0.8)";
+                        else ictx.fillStyle = "rgba(225,225,225,0.8)";
+                    } else ictx.fillStyle = "rgba(255,255,255,0.4)";
+
+                    for (var c = 0; c < mp; c++) {
+                        if (++i >= startPoint)break;
+                        smi = startPoint - i;
+                        spi = startPoint + i;
+                        ictx.drawImage(icvs, spi, 0, smi, totalWidth,
+                            spi + 1, 0, smi, totalWidth);
+
+                        ictx.drawImage(icvs, 0, 0, smi + 1, totalWidth,
+                            -1, 0, smi + 1, totalWidth);
+
+                        ictx.drawImage(icvs, 0, spi, totalWidth, smi,
+                            0, spi + 1, totalWidth, smi);
+
+                        ictx.drawImage(icvs, 0, 0, totalWidth, smi + 1,
+                            0, -1, totalWidth, smi + 1);
+                    }
+                    mp--;
+                    if (mp < 1)mp = 1;
+                    ictx.fillRect(spi + 1, 0, 1, totalWidth);
+                    ictx.fillRect(smi - 1, 0, 1, totalWidth);
+                    ictx.fillRect(0, spi + 1, totalWidth, 1);
+                    ictx.fillRect(0, smi - 1, totalWidth, 1);
+                }
+            }
+        }
+
+        lastPreviewURI = icvs.toDataURL();//the last one, large size, is cached for revisiting the menu
+
+        var browseIconWidth = (devicePixelRatio > 1 ? 38 : 19);
+        var browseIconHalfWidth = Math.floor(browseIconWidth * 0.5);
+        //chrome.browserAction.setIcon({imageData:ictx.getImageData(startPoint-browseIconHalfWidth, startPoint-browseIconHalfWidth, browseIconWidth, browseIconWidth)});
+
+        var tmpCvs = document.createElement('canvas');
+        tmpCvs.width = browseIconWidth, tmpCvs.height = browseIconWidth;
+        var tctx = tmpCvs.getContext("2d");
+        tctx.drawImage(icvs, startPoint - browseIconHalfWidth, startPoint - browseIconHalfWidth, browseIconWidth, browseIconWidth, 0, 0, browseIconWidth, browseIconWidth);
+        var pathData = {};
+        pathData[browseIconWidth] = tmpCvs.toDataURL();
+        chrome.runtime.sendMessage({browserIconMsg: true, path: (pathData)}, function () {
+        });
+
+        setPixelPreview(lastPreviewURI, hex, lasthex);
+
+        if (popupsShowing > 0) {
+            sendDataToPopup();
+        }
+        isUpdating = false;
+    }
+
+    function sendDataToPopup() {
+        chrome.runtime.sendMessage({
+            setPreview: true,
+            previewURI: lastPreviewURI,
+            hex: hex,
+            lhex: lasthex,
+            elemTool: rgb.r,
+            cg: rgb.g,
+            cb: rgb.b
+        }, function (response) {
+        });
+    }
+
+    function getMain2dContext() {
+        var context = icvs.getContext("2d");
+        if (context) return context;
+        else {
+            initializeCanvas();
+            return icvs.getContext("2d");
+        }
+    }
+
+    function getMain3dContext() {
+        if (gl) return gl;
+        else {
+            initializeCanvas();
+            return gl;
+        }
+    }
+
+    function initializeCanvas() {
+        gl = 0;
+        icvs = document.createElement('canvas');//icon canvas
+        icvs.width = totalWidth;
+        icvs.height = totalWidth;
+        if (webGlAvail) {
+            gl = icvs.getContext("webgl");
+
+            var squareVerticesBuffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+            var vertices = [
+                1.0, 1.0, 0.0,//top right
+                -1.0, 1.0, 0.0,
+                1.0, -1.0, 0.0,
+                -1.0, -1.0, 0.0
+            ];
+            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
+
+            var textureCoordBuffer = gl.createBuffer();
+            gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
+            var textureCoordinates = [
+                // Front
+                1.0, 1.0,
+                0.0, 1.0,
+                1.0, 0.0,
+                0.0, 0.0
+            ];
+            gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(textureCoordinates), gl.STATIC_DRAW);
+
+            var fragShader = "" +
+                "precision mediump float;" + "\n" +
+                "varying highp vec2 vTextureCoord;" + "\n" +
+                "uniform float fishEyeScale;" + "\n" +
+                "uniform sampler2D uSampler;" + "\n" +
+                "void main(void) {" + "\n" +
+                " float texSizeFracOnePix=1.0 / 128.0;" + "\n" +
+                " float halfTexSizeFracOnePix=texSizeFracOnePix * 0.5;" + "\n" +
+                " vec2 ctr=vec2(0.5,0.5) + vec2(halfTexSizeFracOnePix,-halfTexSizeFracOnePix);" + "\n" +
+                " vec2 agl=(vTextureCoord.xy - ctr.xy);" + "\n" +
+                " float dis=distance(ctr,vTextureCoord) / fishEyeScale;" + "\n" +
+                " vec2 get=ctr + (agl * dis);" + "\n" +
+                " vec4 bcolor=texture2D(uSampler, get);" + "\n" +
+                " vec2 res=get * 128.0;" + "\n" +
+                " ivec2 geb=ivec2(res);" + "\n" +
+                " vec4 pcolor = texture2D(uSampler, ctr);//picked color" + "\n" +
+                " vec4 ccolor = vec4(0.0,0.0,0.0,1.0);//crosshair color" + "\n" +
+                " if(pcolor.r + pcolor.g + pcolor.b < 1.5){" + "\n" +
+                "  ccolor = vec4(1.0,1.0,1.0,1.0);" + "\n" +
+                " }" + "\n" +
+                " if( geb.x == 64 && geb.y == 63 ){" + "\n" +
+                "  if( res.x < 64.1 || res.x > 64.9  || res.y > 63.9 || res.y < 63.1 	){" + "\n" +
+                "   bcolor = mix(bcolor,ccolor,0.8);" + "\n" +
+                "  }" + "\n" +
+                " }" + "\n" +
+                " gl_FragColor = bcolor;" + "\n" +
+                "}";
+
+            var vertShader = "" +
+                "attribute vec3 aVertexPosition;" + "\n" +
+                "attribute vec2 aTextureCoord;" + "\n" +
+                "varying highp vec2 vTextureCoord;" + "\n" +
+                "void main(void) {" + "\n" +
+                " gl_Position = vec4(aVertexPosition, 1.0);" + "\n" +
+                " vTextureCoord = aTextureCoord;" + "\n" +
+                "}";
+
+            var fshader = gl.createShader(gl.FRAGMENT_SHADER);
+            var vshader = gl.createShader(gl.VERTEX_SHADER);
+
+            gl.shaderSource(fshader, fragShader);
+            gl.shaderSource(vshader, vertShader);
+
+            gl.compileShader(fshader);
+            if (!gl.getShaderParameter(fshader, gl.COMPILE_STATUS)) {
+                webGlAvail = false;
+                console.log("An error occurred compiling the frag shaders: " + gl.getShaderInfoLog(fshader));
+            }
+
+            gl.compileShader(vshader);
+            if (!gl.getShaderParameter(vshader, gl.COMPILE_STATUS)) {
+                webGlAvail = false;
+                console.log("An error occurred compiling the vertex shaders: " + gl.getShaderInfoLog(vshader));
+            }
+
+            shaderProgram = gl.createProgram();
+            gl.attachShader(shaderProgram, vshader);
+            gl.attachShader(shaderProgram, fshader);
+            gl.linkProgram(shaderProgram);
+
+            if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
+                webGlAvail = false;
+                console.log("Unable to initialize the shader program.");
+                console.log(gl.getProgramInfoLog(shaderProgram));
+            }
+
+            gl.useProgram(shaderProgram);
+
+            var vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
+            gl.enableVertexAttribArray(vertexPositionAttribute);
+
+            var textureCoordAttribute = gl.getAttribLocation(shaderProgram, "aTextureCoord");
+            gl.enableVertexAttribArray(textureCoordAttribute);
+
+            textureSampPosition = gl.getUniformLocation(shaderProgram, "uSampler");
+            fishEyeScalePosition = gl.getUniformLocation(shaderProgram, "fishEyeScale");
+
+            texture = document.createElement('canvas');//icon canvas
+            texture.width = 128;
+            texture.height = 128;
+            texturectx = texture.getContext("2d");
+
+            gl.activeTexture(gl.TEXTURE0);
+            snapTexture = gl.createTexture();
+            gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
+            gl.bindTexture(gl.TEXTURE_2D, snapTexture);
+            gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+            gl.generateMipmap(gl.TEXTURE_2D);
+            gl.uniform1i(textureSampPosition, 0);
+
+            gl.bindBuffer(gl.ARRAY_BUFFER, textureCoordBuffer);
+            gl.vertexAttribPointer(textureCoordAttribute, 2, gl.FLOAT, false, 0, 0);
+
+            gl.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+            gl.vertexAttribPointer(vertexPositionAttribute, 3, gl.FLOAT, false, 0, 0);
+        }
+    }
+
+    function reqLis(request, sender, sendResponse) {
+        var resp = {result: true};
+        if (request.enableColorPicker) {
+            resp.wasAlreadyEnabled = enableColorPicker()
+            if (request.workerHasChanged) lsnaptabid = -1;
+            if (resp.wasAlreadyEnabled) {
+                resp.hex = hex;
+                resp.lhex = lasthex;
+                resp.previewURI = lastPreviewURI;
+                resp.FeHelper.elemTool = rgb.r;
+                resp.cg = rgb.g;
+                resp.cb = rgb.b;
+            }
+        } else if (request.doPick) {
+            picked()
+        } else if (request.setPickerImage) {
+            c.src = request.pickerImage;
+        }
+        resp.isPicking = !isLocked;
+        sendResponse(resp);
+    }
+
+    function init() {
+
+        disableColorPicker();
+        chrome.runtime.onMessage.removeListener(reqLis);
+        chrome.runtime.onMessage.addListener(reqLis);
+
+        chrome.runtime.onConnect.addListener(function (port) {
+            if (port.name == "popupshown") {
+                popupsShowing++;
+                port.onDisconnect.addListener(function (msg) {
+                    popupsShowing--;
+                    if (popupsShowing < 0)popupsShowing = 0;
+                });
+            }
+        });
+    }
+
+    return {
+        init: init
+    };
+
+
+})();
+
+FeHelper.ColorPicker.init();

+ 136 - 0
chrome/static/js/colorpicker/elem-tool.js

@@ -0,0 +1,136 @@
+var FeHelper = window.FeHelper || {};
+
+FeHelper.elemTool = {
+/*******************************************************************************
+ Usage A: 
+         elemTool.elm('div',{'id':'hello','event':['click',function(){alert('hi');}]},[
+           elemTool.txt('text inside block element'),
+           elemTool.elm('hr',{'style':'clear:both;'})
+         ],document.body);
+         
+ Usage B: 
+         var myelm = elemTool.elm('div',{'id':'hello','event':['click',function(){alert('hi');}]},[
+           elemTool.txt('text inside block element'),
+           elemTool.elm('hr',{'style':'clear:both;'})
+         ]);
+         
+         document.body.appendChild(myelm);
+            OR
+         elemTool.insertNode(myelm, document.body);
+         
+ Creates:
+         <div id="hello">
+           text inside block element
+           <hr style="clear:both;">
+         </div>
+         
+         Where clicking the text or hr displays 'hi'
+         
+ Pattern:
+         elemTool.elm('div',{'attribute':'one'},[elemTool.txt('children')],document.body);
+         
+         <body><div attribute="one">children</div></body>
+         
+   Conclusions: you may nest elemTool.elm calls in exactly the same way 
+                as you would nest HTML elements.
+ Parameters: 
+   nodeType
+          node type such as 'img' 'div' or 'a'
+   attributes an object {} that contains attributes.  Once special attribute 
+          'events' may be used to specify events as follows:
+          {'href':'#','events':[['mouseover',callfn,false],['mouseout',callfn2]]}
+          to ensure these listeners are attached see appendTo below.
+          the format for events is [eventType,callback,useCapture], you may also 
+          specify a single event.  See appendTo below for event attachment info
+          
+          'loadevents' may be used to specify early attach events as follows:
+          {'loadevents':[['load',loadedFn,false],['load',loadedFn2]],'src':'img.png'}
+          load events are attached immediately in the order they are processed.  If
+          you wish load events to be attached before src is defiend to counter an IE
+          but where cached images load event fires immediately, 
+          then sepecify loadevents before src
+   addchilds an array [] containing nodes to be appended as children, could contain
+          an array of calls to elemTool.elm which create this array of nodes.
+   appnedTo should ONLY be specified on the last element that needs to be created
+          which means the TOP level element (or the final parameter on the first 
+          or outter most call to elemTool.elm).
+ Empty Patteren:
+          elemTool.elm('div',{},[],document.body);
+*******************************************************************************/
+	elm : function(nodeType,attributes,addchilds,appnedTo){
+		var ne=document.createElement(nodeType),i,l;
+		if(attributes){
+			if( attributes.event || attributes.events ){
+				var lev=attributes.event || attributes.events;
+				if(typeof(lev[0])=='string') ne.addEventListener(lev[0],lev[1],lev[2]);
+				else if(lev.length)
+					for(i=0,l=lev.length;i<l;i++)
+						ne.addEventListener(lev[i][0],lev[i][1],lev[i][2]);
+			}
+		}
+		for( i in attributes ){
+			if( i.substring(0,5) == 'event' ){
+				//handled earlier
+			}else if( i == 'checked' || i == 'selected'){
+				if(attributes[i])ne.setAttribute(i,i);
+			}else ne.setAttribute(i,attributes[i]);
+		}
+		if(addchilds){
+			for( i=0,l=addchilds.length;i<l;i++ ){
+				if(addchilds[i])ne.appendChild(addchilds[i]);//you probably forgot a comma when calling the function
+			}
+		}
+		if(appnedTo){
+			this.insertNode(ne, appnedTo);
+		}
+	
+		return ne;//identifier unexpected error pointing here means you're missing a comma on the row before inside an array of nodes addchilds
+	},
+	/*elemTool.txt creates text nodes, does not support HTML entiteis */
+	txt : function(textContent){
+		return document.createTextNode(textContent);
+	},
+	/*elemTool.ent creates text nodes that may or may not contain HTML entities.  From a
+	single entity to many entities interspersed with text are all supported by this */
+	ent : function(textContent){
+		return document.createTextNode(this.unescapeHtml(textContent));
+	},
+	/*elemTool.paragraphs creates an array of nodes that may or may not contain HTML entities.*/
+	paragraphs : function(textContent){
+		var textPieces=textContent.split("\n");
+		var elmArray=[];
+		for(var i=0,l=textPieces.length;i<l;i++){
+			elmArray.push(elemTool.elm('p',{},[elemTool.ent(textPieces[i])]));
+		}
+		return elmArray;
+	},
+	insertNode : function(newNode, parentElem, optionalInsertBefore){
+		if(!parentElem)parentElem=document.body;
+		if(optionalInsertBefore && optionalInsertBefore.parentNode == parentElem){
+			parentElem.insertBefore(newNode,optionalInsertBefore);
+		}else{
+			parentElem.appendChild(newNode);
+		}
+	},
+	insertNodes : function(newNodes, parentElem, optionalInsertBefore){
+		if(typeof(newNodes)!='array')
+			this.insertNode(newNodes, parentElem, optionalInsertBefore);
+		else{
+			for(var i=0,l=newNodes.length;i<l;i++){
+				this.insertNode(newNodes[i], parentElem, optionalInsertBefore, true);
+			}
+		}
+	},
+	empty : function(node){
+		while(node.lastChild)node.removeChild(node.lastChild);
+	},
+	unescapeHtml : function(str) { //trick used to make HTMLentiites work inside textNodes
+		if(str.length < 1)return str;
+		var temp = document.createElement("div");
+		str = str.replace(/<\/?\w(?:[^"'>]|"[^"]*"|'[^']*')*>/gmi, '');
+		temp.innerHTML = str;
+		var result = temp.childNodes[0].nodeValue;
+		this.empty(temp);
+		return result;
+	}
+}

+ 60 - 6
chrome/static/js/fe-background.js

@@ -31,11 +31,11 @@ var BgPageInstance = (function () {
             options.title = "温馨提示";
         }
 
-        chrome.notifications.create('',{
-            type:'basic',
-            title:options.title,
+        chrome.notifications.create('', {
+            type: 'basic',
+            title: options.title,
             iconUrl: chrome.runtime.getURL(options.icon),
-            message:options.message
+            message: options.message
         });
 
     };
@@ -252,7 +252,7 @@ var BgPageInstance = (function () {
         baidu.contextMenuId = chrome.contextMenus.create({
             title: "FeHelper",
             contexts: ['page', 'selection', 'editable', 'link'],
-            documentUrlPatterns:['http://*/*','https://*/*']
+            documentUrlPatterns: ['http://*/*', 'https://*/*']
         });
         chrome.contextMenus.create({
             title: "JSON格式化",
@@ -342,6 +342,19 @@ var BgPageInstance = (function () {
                 _goCompressTool();
             }
         });
+        chrome.contextMenus.create({
+            type: 'separator',
+            contexts: ['all'],
+            parentId: baidu.contextMenuId
+        });
+        chrome.contextMenus.create({
+            title: "页面取色器",
+            contexts: ['page', 'selection', 'editable'],
+            parentId: baidu.contextMenuId,
+            onclick: function (info, tab) {
+                _showColorPicker();
+            }
+        });
     };
 
     /**
@@ -366,6 +379,42 @@ var BgPageInstance = (function () {
         }
     };
 
+    /**
+     * 显示color picker
+     * @private
+     */
+    var _showColorPicker = function () {
+        chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
+            var tab = tabs[0];
+            var tabid = tab.id;
+            var port = chrome.tabs.connect(tabid, {name: "popupshown"});
+            chrome.tabs.sendMessage(tabid, {enableColorPicker: true}, function (response) {
+                chrome.tabs.sendMessage(tabid, {doPick: true}, function (r) {
+                });
+            });
+        });
+    };
+
+    /**
+     * 将网页截成一张图,实现取色
+     * @param callback
+     * @private
+     */
+    var _drawColorPicker = function (callback) {
+        chrome.tabs.query({active: true, currentWindow: true}, function (tabs) {
+            var tab = tabs[0];
+            var tabid = tab.id;
+            chrome.tabs.captureVisibleTab(null, {format: 'png'}, function (dataUrl) {
+                chrome.tabs.sendMessage(tabid, {
+                    setPickerImage: true,
+                    pickerImage: dataUrl
+                }, function (response) {
+                    callback && callback();
+                });
+            });
+        });
+    };
+
     /**
      * 接收来自content_scripts发来的消息
      */
@@ -428,6 +477,10 @@ var BgPageInstance = (function () {
             else if (request.type == MSG_TYPE.FROM_POPUP) {
                 _runHelper(request.config);
             }
+            // color picker
+            else if (request.type == "color-picker:newImage") {
+                _drawColorPicker(callback);
+            }
 
             return true;
         });
@@ -444,7 +497,8 @@ var BgPageInstance = (function () {
 
     return {
         init: _init,
-        runHelper: _runHelper
+        runHelper: _runHelper,
+        showColorPicker: _showColorPicker
     };
 })();
 

+ 9 - 4
chrome/static/js/fe-popup.js

@@ -10,10 +10,15 @@ $(function () {
         var msgType = $(this).attr('data-msgtype');
         var isUseFile = $(this).attr('data-usefile');
 
-        bgPage.BgPageInstance.runHelper({
-            msgType:MSG_TYPE[msgType],
-            useFile:isUseFile
-        });
+        if (msgType == 'COLOR_PICKER') {
+            bgPage.BgPageInstance.showColorPicker();
+        } else {
+            bgPage.BgPageInstance.runHelper({
+                msgType: MSG_TYPE[msgType],
+                useFile: isUseFile
+            });
+        }
+
         window.close();
     });
 });

+ 3 - 0
chrome/static/js/mod/mod_manifest.js

@@ -33,6 +33,9 @@ importScript("js/fcp/fcp-main.js");
 importScript("js/fe-helper.js");
 importScript("js/wpo/fe-calc-wpo.js");
 
+importScript("js/colorpicker/elem-tool.js");
+importScript("js/colorpicker/colorpicker.js");
+
 importScript("js/jsonformat/json-format-dealer.js");
 importScript("js/jsonformat/json-format-ent.js");
 importScript("js/jsonformat/contentscript-jsonformat.js");

Plik diff jest za duży
+ 0 - 0
chrome/template/fehelper_popup.html


Niektóre pliki nie zostały wyświetlone z powodu dużej ilości zmienionych plików