阮一峰的详解
- 一个 demo 彻底明确 fileReader 的应用 demo 预览
- demo 在 move 的时候的地位还须要进一步进行相干的计算,当初的地位计算出错了
<!DOCTYPE html>
<html lang="en">
<head>
<title>fileReader + canvas 预览剪切 demo</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
canvas {border: 1px solid red;}
.mergeBox {
display: inline-block;
position: relative;
width: 200px;
height: 200px;
z-index: 0;
top: 0;
overflow: hidden;
}
#mergeCanvas {
position: absolute;
top: 0;
left: 0;
z-index: 0;
width: 200px;
height: 200px;
}
.mergeDiv {
display: none;
position: absolute;
z-index: 0;
top: 0;
left: 0;
width: 200px;
height: 200px;
background-image: url('http://qinyuanqiblog.github.io/images/angular/shape_lingxing.png');
background-repeat: no-repeat;
background-size: 200px, 200px;
}
label {
display: block;
width: 100px;
height: 50px;
font-size: 20px;
color: #fff;
line-height: 50px;
background: #999;
cursor: pointer;
text-align: center;
border-radius: 10px;
}
input[type='file'] {display: none;}
.preview-area {display: none;}
</style>
</head>
<body>
<label for="file"> 抉择文件 </label>
<input id="file" type="file" accept="image/*">
<div class="preview-area">
<canvas id="previewCanvas"></canvas>
<canvas id="compareCanvas"></canvas>
<button class="merge"> 合成 </button>
<button class="inverse"> 反色 </button>
<div class="mergeBox">
<canvas id="mergeCanvas"></canvas>
<div class="mergeDiv"> </div>
</div>
<canvas id="clipCanvas"></canvas>
<button class="clip"> 确认裁剪 </button>
<img src=""class="makePreview"alt="">
</div>
</body>
<script>
/** 思路
*
* 1. 应用 fileReader API 读取到图片
* 2. 生成 previewCanvas 预览图片
* 3. 在 previewCanvas 上解决图片的滤镜和裁剪
* 3.1 在 previewCanvas 上进行图片滤镜解决 (canvas 的像素级解决)
* 3.2 把须要截取的图像写入到 compareCanvs 上,之后再和 previewCanvas 比照, 生成 clipCanvas(裁剪图片之后的 canvas)
* 3.3 在 clipCanvas 上进行拖动并生成预览
* 3.3.1 图片平移这一块应用到了 css3 的 matrix 相干的常识 其实也能够应用定位来实现的,起初的这个版本我就改用了定位来做的
* transform:matrix(a,b,c,d,e,f)
* a 程度缩放 (1)
* b 程度歪斜 (0)
* c 垂直歪斜 (0)
* d 垂直缩放 (1)
* e 程度位移 (0)
* f 垂直位移 (0)
* 3.4 把 clipCanvas 上的图片转换成 blob 对象的地址 并生成预览图片
*
*/
var input = document.querySelector('input');
var previewCanvas = document.querySelector('#previewCanvas');
var compareCanvas = document.querySelector('#compareCanvas');
var mergeCanvas = document.querySelector('#mergeCanvas');
var clipCanvas = document.querySelector('#clipCanvas');
var previewCtx = previewCanvas.getContext('2d');
var compareCtx = compareCanvas.getContext('2d');
var mergeCtx = mergeCanvas.getContext('2d');
var clipCtx = clipCanvas.getContext('2d');
var mergeDiv = document.querySelector('.mergeDiv');
var inverse = document.querySelector('.inverse');
var merge = document.querySelector('.merge');
var clip = document.querySelector('.clip');
var previewWidth = compareCanvas.width = previewCanvas.width = 200;
var previewHeight = compareCanvas.height = previewCanvas.height = 200;
var isDrag = false;
var disX = 0;
var disY = 0;
var clipDx = 0;
var clipDy = 0;
var previewImg = null;
var compareImg = null;
clipCanvas.width = previewWidth;
clipCanvas.height = previewHeight;
// 读取文件
input.addEventListener('change', readerFile);
// 生成比照图
function createCompareImg() {compareImg = new Image();
compareImg.crossOrigin = "Anonymous"; // 解决跨域
compareImg.src = 'http://qinyuanqiblog.github.io/images/angular/shape_lingxing.png';
compareImg.onload = function() {compareCtx.drawImage(this, 0, 0, previewWidth, previewHeight);
}
}
// 读取文件, 生成 canvas 预览
function readerFile() {var file = this.files[0];
// FileReader API 用于读取文件,即把文件内容读入内存
var reader = new FileReader();
// 读取文件胜利
reader.onload = function() {createPreviewToCanvas(reader.result);
}
// 返回一个基于 Base64 编码编码的数据 URI 对象
reader.readAsDataURL(file);
}
/**
* 生成 canvas 预览图,不便后续解决
* @param dataURL {object} 一个基于 Base64 编码编码的数据 URI 对象
*/
function createPreviewToCanvas(dataURL) {previewImg = new Image();
previewImg.src = dataURL;
previewImg.onload = function() {previewCtx.drawImage(previewImg, 0, 0, previewWidth, previewHeight);
}
createCompareImg();
document.querySelector('.preview-area').style.display = 'block';
}
// 合并图片
merge.addEventListener('click', function() {
mergeDiv.style.display = 'block';
mergeCanvas.width = previewWidth;
mergeCanvas.height = previewHeight;
mergeCtx.drawImage(previewImg, 0, 0, previewWidth, previewHeight);
});
// 滤镜解决
inverse.addEventListener('click', function() {var previewData = previewCtx.getImageData(0, 0, previewWidth, previewHeight);
for (var i = 0; i < previewData.data.length; i += 4) {previewData.data[i] = 255 - previewData.data[i];
previewData.data[i + 1] = 255 - previewData.data[i + 1];
previewData.data[i + 2] = 255 - previewData.data[i + 2];
previewData.data[i + 3] = 255;
}
previewCtx.putImageData(previewData, 0, 0);
})
mergeDiv.addEventListener('mousedown', mouseDownFn);
mergeDiv.addEventListener('mousemove', mouseMoveFn);
mergeDiv.addEventListener('mouseup', mouseUpFn);
mergeDiv.addEventListener('mouseleave', mouseUpFn);
// 裁剪图片
clip.addEventListener('click', createClipPreview);
// 查看剪切之后的图片
function createClipPreview() {clipImg(clipDx, clipDy)
var imgSrc = _base64ToBlob(clipCanvas.toDataURL());
document.querySelector('.makePreview').src = imgSrc;
}
/**
* base64 编码数据转成 blob 对象
* @param dataURL {object} 一个基于 Base64 编码编码的数据 URI 对象
* @return result {blob object} 返回一个能够间接浏览的本地图片地址
*/
function _base64ToBlob(dataURL) {
// 获取源数据类型
var mimeString = dataURL.split(',')[0].split(':')[1].split(';')[0];
// 取到 base64 转码后的源数据
var str = dataURL.split(',')[1];
//base64 解码
str = window.atob(str);
// 应用一个 Uint8Array 来存放数据
var utf8Array = new Uint8Array(str.length);
for (var i = 0; i < str.length; i++) {utf8Array[i] = str.charCodeAt(i);
}
// 转换成一个 blob 对象
var blob = new Blob([utf8Array], {type: mimeString});
// 生成能够间接拜访的本地地址
var src = URL.createObjectURL(blob);
return src;
}
// 裁剪图片
function clipImg(dx, dy) {var proviewImgData = previewCtx.getImageData(-dx, -dy, previewWidth, previewHeight);
var compareImgData = compareCtx.getImageData(0, 0, previewWidth, previewHeight);
for (var i = 3; i < compareImgData.data.length; i += 4) {if (compareImgData.data[i] !== 0) {proviewImgData.data[i] = 0;
}
}
clipCtx.putImageData(proviewImgData, 0, 0);
}
var mergeCanvasLeft = 0;
var mergeCanvasTop = 0;
function mouseDownFn(e) {
var event = e || ev;
disX = event.offsetX;
disY = event.offsetY;
mergeCanvasLeft = mergeCanvas.style.left == false ? 0 : mergeCanvas.style.left;
mergeCanvasTop = mergeCanvas.style.top == false ? 0 : mergeCanvas.style.top;
isDrag = true;
}
function mouseMoveFn(e) {if (isDrag) {
var event = e || ev;
var left = event.offsetX - disX + parseInt(mergeCanvasLeft);
var top = event.offsetY - disY + parseInt(mergeCanvasTop);
// 也能够应用矩阵或者是 translate 来做,我当初的做法是改成了定位的模式
// mergeCanvas.style.transform = 'matrix(1,0,0,1,' + left + ',' + top + ')';
mergeCanvas.style.left = left + 'px';
mergeCanvas.style.top = top + 'px';
// 裁剪图片 生成预览图
clipImg(left, top);
// 裁剪地位管制
clipDx = left;
clipDy = top;
}
}
function mouseUpFn() {isDrag = false;}
</script>
</html>