JavaScript 马赛克

来源:互联网 发布:mpu9250 九轴融合算法 编辑:程序博客网 时间:2024/04/30 09:31
<html>    <head>        <meta charset="utf8" />        <title>马赛克(mosaic)</title>        <style>        body {            background: gray;            color: white;            text-align: center;        }        .marginTop {            margin-top: 10px;        }        #mosaicPixelResolutionRange {            width: 350px;        }        </style>    </head>    <body>        <div id="mosaicType" class="marginTop">马赛克类型(mosaic type):</div>        <input type="radio" name="mosaicType" value="square" checked />square        <input type="radio" name="mosaicType" value="triangle"/>triangle        <input type="radio" name="mosaicType" value="circle"/>circle        <input type="radio" name="mosaicType" value="diamond"/>diamond        <input type="radio" name="mosaicType" value="start1"/>start1        <input type="radio" name="mosaicType" value="start2"/>start2        <div id="mosaicPixelResolution" class="marginTop">马赛克像素分辨率(mosaic pixel resolution):</div>        <input id="mosaicPixelResolutionRange" type="range" min="1" max="30" step="0.1" value="0" />        <p>注意: 该demo若在本地运行, 则必须修改"chrome快捷方式"->"属性"->"目标",<br/>添加启动参数"--allow-file-access-from-files", 允许跨域访问.</p>        <div id="imgContainer" class="marginTop"></div>        <script>            var mosaicClassName = "mosaicImg";            var doublePI = Math.PI * 2;            var quarterPI = Math.PI / 4;            //方括号([])表示字符范围            //点(.)匹配除“\r\n”之外的任何单个字符。要匹配包括“\r\n”在内的任何字符,请使用像“[\s\S]”的模式。            //var reg = new RegExp("[object.Array]");            //\s是匹配所有空白字符,\S是匹配所有非空白字符搜索,那么[\s\S]这个组合就可以匹配所有字符了。            //var reg = new RegExp("[object[//s//S]*Array]");            //\w匹配包括下划线的任何单词字符。类似但不等价于“[A-Za-z0-9_]”,这里的"单词"字符使用Unicode字符集。\W匹配任何非单词字符。等价于“[^A-Za-z0-9_]”。            var arrayReg = new RegExp("[object[//w//W]*Array]");            //判断是否是数字类型            function isNumber(obj) {                return typeof obj === "number";            }            //判断是否是数组, typeof Array = "object".普通数组是[object Array], 图像数据的数组是[object Uint8ClampedArray]            function isArray(obj) {                return arrayReg.test(Object.prototype.toString.call(obj));            }            //判断是否是对象, typeof Object = "object"            function isObject(obj) {                return Object.prototype.toString.call(obj) === "[object Object]";            }            //获取打马的类型            function getMosaicType() {                var mosaicTypes = document.getElementsByName("mosaicType");                for(var i=0; i < mosaicTypes.length; i++) {                    if(mosaicTypes[i].checked) {                        return mosaicTypes[i].value;                    }                }            }            //获取马赛克像素分辨率            function getMosaicPixelResolution() {                var mosaicPixelResolutionRange = document.getElementById("mosaicPixelResolutionRange");                //从input type="range" 控件中拿出的value是string类型的                return Number(mosaicPixelResolutionRange.value);            }            //设置马赛克类型提示文本            function setMosaicTypeText(type) {                var mosaicType = document.getElementById("mosaicType");                var strArr = mosaicType.innerHTML.split(":");                if(strArr.length > 1) {                    mosaicType.innerHTML = strArr[0] + ":" + type;                } else {                    mosaicType.innerHTML += ":" + type;                }            }            //设置马赛克像素分辨率滑动条提示文本            function setMosaicPixelResolutionRangeText(resolution) {                var mosaicPixelResolution = document.getElementById("mosaicPixelResolution");                var strArr = mosaicPixelResolution.innerHTML.split(":");                if(strArr.length > 1) {                    mosaicPixelResolution.innerHTML = strArr[0] + ":" + resolution;                } else {                    mosaicPixelResolution.innerHTML += (":" + resolution);                }            }            //马赛克类型单选按钮被点击时触发            function onMosaicTypeRadioClick() {                var type = event.target.value;                setMosaicTypeText(type);                renderAll(type, undefined);            }            //马赛克像素分辨率滑动条的值改变时触发            function onMosaicPixelResolutionRangeChange() {                var resolution = event.target.value;                setMosaicPixelResolutionRangeText(resolution);                renderAll(undefined, Number(resolution));            }            //渲染所有图像            function renderAll(mosaicType, mosaicPixelResolution) {                if(mosaicType === undefined) {                    mosaicType = getMosaicType();                }                if(mosaicPixelResolution  === undefined) {                    mosaicPixelResolution = getMosaicPixelResolution();                }                var elems = document.getElementsByClassName(mosaicClassName);                for(var i=0; i<elems.length; i++) {                    elems[i].render(mosaicType, mosaicPixelResolution);                }            }            //创建img,然后将其隐藏,用同等大小的canvas替代            function createImg(id, cls, src) {                var imgContainer = document.getElementById("imgContainer");                 var img = new Image();                img.onload = function() {                    var canvas = document.createElement("canvas");                    //id必须直接设置,而class必须通过attribute属性来设置                    canvas.id = id;                    if(cls) {                        canvas.setAttribute("class", cls);                    }                    //如果style中有设置width或height,就用它们的设置                    var width, height;                    if(canvas.style.width) {                        width = canvas.style.width;                    } else {                        width = img.width;                    }                    if(canvas.style.height) {                        height = canvas.style.height;                    } else {                        height = img.height;                    }                    canvas.width = width;                    canvas.height = height;                    imgContainer.appendChild(canvas);                    var ctx = canvas.getContext("2d");                    ctx.drawImage(img, 0, 0, width, height);                    canvas.imageData = ctx.getImageData(0, 0, width, height);                }                img.src = src;            }            //(x,y)处绘制长度为dx,dy的形状            function drawRegion(ctx, imageData, x, y, type, resolution) {                //每个点用4个字节存储, 分别是RGBA, alpha通道(0-255; 0是透明的,255是完全可见的), 数据按行排列。                //注意: 数组的索引必须是一个整数                var halfResolution = resolution * .5;                var cx = x + halfResolution;                var cy = y + halfResolution;                var tmpX = cx;                var tmpY = cy;                if(cx > imageData.width || cy > imageData.height) {                    if(cx > imageData.width) {                        tmpX = cx - halfResolution                    }                    if(cy > imageData.height) {                        tmpY = cy - halfResolution;                    }                }                tmpX = Math.floor(tmpX);                tmpY = Math.floor(tmpY);                var index = (tmpY * imageData.width + tmpX) * 4;                 var r = imageData.data[index];                var g = imageData.data[index + 1];                var b = imageData.data[index + 2];                var a = imageData.data[index + 3];                ctx.fillStyle = "rgba(" + [r,g,b,a].join(",") + ")";                switch(type) {                    case "square":                        ctx.fillRect(x, y, resolution, resolution);                    break;                    case "triangle":                        ctx.beginPath();                        ctx.moveTo(cx, y);                        ctx.lineTo(x + resolution, y + resolution);                        ctx.lineTo(x, y + resolution);                        ctx.closePath();                        ctx.fill();                    break;                    case "circle":                        ctx.beginPath();                        ctx.arc(cx, cy, halfResolution, 0, doublePI);                        ctx.fill();                    break;                    case "diamond":                        var diamondResolution = Math.SQRT2 * halfResolution;                        var halfDiamondResolution = diamondResolution / 2;                        ctx.save();                        ctx.translate(cx, cy);                        ctx.rotate(quarterPI);                        ctx.fillRect(-halfDiamondResolution, -halfDiamondResolution, diamondResolution, diamondResolution);                        ctx.restore();                    break;                    case "start1":                        var oneThirdResolution = resolution / 3;                        ctx.beginPath();                        ctx.moveTo(cx, y);                        ctx.lineTo(x + resolution, y + resolution);                        ctx.lineTo(x, y + oneThirdResolution);                        ctx.lineTo(x + resolution, y + oneThirdResolution);                        ctx.lineTo(x, y + resolution);                        ctx.closePath();                        ctx.fill();                    break;                    case "start2":                        var oneThirdResolution = resolution / 3;                        ctx.beginPath();                        ctx.moveTo(cx, y);                        ctx.lineTo(x + resolution, y + 2 * oneThirdResolution);                        ctx.lineTo(x, y + 2 * oneThirdResolution);                        ctx.closePath();                        ctx.fill();                        ctx.beginPath();                        ctx.moveTo(cx, y + resolution);                        ctx.lineTo(x + resolution, y + oneThirdResolution);                        ctx.lineTo(x, y + oneThirdResolution);                        ctx.closePath();                        ctx.fill();                    break;                }            }            function init() {                setMosaicTypeText(getMosaicType());                setMosaicPixelResolutionRangeText(getMosaicPixelResolution());                var mosaicTypes = document.getElementsByName("mosaicType");                for(var i=0; i<mosaicTypes.length; i++) {                    mosaicTypes[i].addEventListener("click", onMosaicTypeRadioClick);                }                mosaicPixelResolutionRange.addEventListener("change", onMosaicPixelResolutionRangeChange);                HTMLCanvasElement.prototype.render = function(mosaicType, mosaicPixelResolution) {                    if(!this.imageData || !isArray(this.imageData.data) || !isNumber(this.imageData.width) || !isNumber(this.imageData.height)) {                        return;                    }                    var ctx = this.getContext("2d");                    ctx.clearRect(0, 0, this.imageData.width, this.height);                    if(mosaicPixelResolution <= 1) {                        //马赛克像素分辨率等于1的情况不需要处理, 否则太慢了. 一张42KB的图要执行1.3秒. 而直接putImage只要0.5ms                        //ctx.putImageData(this.imageData, 0, 0);                        var dirtyX = 0;                        var dirtyY = 0;                        var dirtyWidth = this.width;                        var dirtyHeight = this.height;                        ctx.putImageData(this.imageData, 0, 0, dirtyX, dirtyY, dirtyWidth, dirtyHeight);                    } else {                        for(var x=0; x <= this.imageData.width; x += mosaicPixelResolution) {                            for(var y=0; y <= this.height; y += mosaicPixelResolution) {                                drawRegion(ctx, this.imageData, x, y, mosaicType, mosaicPixelResolution);                            }                        }                    }                }                createImg("img1", mosaicClassName, "1.jpg");            }            init();            </script>    </body></html>

这里写图片描述

chrome允许跨域访问的方式如下:
Microsof Edge、360安全浏览器的配置方式也基本相同。

这里写图片描述

火狐上不用配置就可以直接预览。

2 0
原创粉丝点击