以前要想在图片上传前,对图片剪裁下,纯用js的话,很难实现。现在有了html5了,腰也不疼了,腿也不抽筋了。
主要用到html5的2个特性:
1、FileReader
FileReader可以把本地文件进行读取并且转化为Base64编码的数据,很便于在html页面里显示。
2、canvas
对图片的放大缩小啊,左移右移啊,实现起来很简单。尤其是它还可以对图片的像素进行操作(红、绿、蓝、透明),最后利用toDataURL方法用图片进行剪裁。美中不足的话,目前还不支持gif格式,有点小遗憾。
下面是我写的一个简易小例子的片段(完整代码在附件里)
选择图片用的是
<input id="upload" type="file" />
选择文件生成Base64及图片加载后初始化canvas的代码:
var upload = $('#upload'); upload.change(function (e) { e.preventDefault(); var file = upload[0].files[0], reader = new FileReader(); reader.onload = function (event) { img.src = event.target.result; var result = img.src.toString().match(/^data:(image\/[a-z+]+);base64,/); if (result) { imgType = result[1]; } }; reader.readAsDataURL(file); return false; }); img.onload = function () { var min = Math.min(img.width, img.height); scale = (bWH - 2 * borderWH) / min; $('#range').attr('min', scale * 100); // 判断下可放缩的范围 if (min >= (bWH - 2 * borderWH)) { $('#range').attr('max', 100); } else { $('#range').attr('max', scale * 100) } canvasScale(true, scale); $('#range').val(scale * 100); }
对图片放缩时,我没有使用canvas的scale方法,因为它会把canvas的大小也一起放缩了,和我想实现的需求不符。我利用的是canvas的drawImage的方法。放大就把dw、dh相应放大,缩小就相应缩小达到类似的效果。
function canvasScale(init, num) { var w = img.width; var h = img.height; scale = num; dw = w * scale; dh = h * scale; if (init) { dx = 0; dy = 0; if (bWH > dw) { dx = (bWH - dw) / 2; } if (bWH > dh) { dy = (bWH - dh) / 2; } } else { if (dx > borderWH) { dx = borderWH; } else if (dx < bWH - borderWH - dw) { dx = bWH - borderWH - dw; } if (dy > borderWH) { dy = borderWH; } else if (dy < bWH - borderWH - dh) { dy = bWH - borderWH - dh; } } // 大图 ctx.clearRect(0, 0, bWH, bWH); ctx.drawImage(img, 0, 0, w, h, dx, dy, dw, dh); // 大图四周的框 canvasPadding(ctx, borderWH, bWH); // 小图 ctxSmall.clearRect(0, 0, sWH, sWH); ctxSmall.drawImage(img, (15 - dx) / scale, (15 - dy) / scale, (bWH - 2 * borderWH) / scale, (bWH - 2 * borderWH) / scale, 0, 0, sWH, sWH); }
最后就剩下一个截取功能了
function canvasToDataURL() { var canvasTmp = document.createElement('canvas'); canvasTmp.width = bWH - 2 * borderWH; canvasTmp.height = bWH - 2 * borderWH; var ctxTmp = canvasTmp.getContext('2d'); ctxTmp.drawImage(img, (15 - dx) / scale, (15 - dy) / scale, (bWH - 2 * borderWH) / scale, (bWH - 2 * borderWH) / scale, 0, 0, canvasTmp.width, canvasTmp.height); // 像素操作 var imgPixels = ctxTmp.getImageData(0, 0, canvasTmp.width, canvasTmp.height); var lenW = imgPixels.width; var lenH = imgPixels.height; var red = $('#red').val(); var green = $('#green').val(); var blue = $('#blue').val(); var opacity = $('#opacity').val(); for (var y = 0; y < lenH; y++) { for (var x = 0; x < lenW; x++) { imgPixels.data[4 * (y * lenW + x) + 0] *= red; imgPixels.data[4 * (y * lenW + x) + 1] *= green; imgPixels.data[4 * (y * lenW + x) + 2] *= blue; imgPixels.data[4 * (y * lenW + x) + 3] = opacity; } } ctxTmp.putImageData(imgPixels, 0, 0, 0, 0, imgPixels.width, imgPixels.height); // 生成对应类型的图片 return canvasTmp.toDataURL(imgType); }
测试如下:
ff,chrome,mx3都支持FileReader和canvas。
mx3下FileReader还有点问题,估计日后会改好。
chrome本地安全问题,需要放到服务器上才能看效果。
ff目前对<input type="range" />还不支持。