版权声明:转载请注明出处—— https://blog.csdn.net/chy555chy/article/details/54648318
<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安全浏览器的配置方式也基本相同。
火狐上不用配置就可以直接预览。