JavaScript 马赛克
Posted 福州-司马懿
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JavaScript 马赛克相关的知识,希望对你有一定的参考价值。
<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安全浏览器的配置方式也基本相同。
火狐上不用配置就可以直接预览。
开发者涨薪指南 48位大咖的思考法则、工作方式、逻辑体系以上是关于JavaScript 马赛克的主要内容,如果未能解决你的问题,请参考以下文章