本篇主要涉及到:

  • 文件上传
  • 图片编辑
  • 图片文件下载

一、文件上传

文件上传目前了解的主要有三种方式:

  • type="file"的input输入框
  • drop拖放事件;
  • 另有"ctrl+V"进行粘贴,但是此方法使用有局限性,如:不支持windows系统文件的复制粘贴(大概理解为windows系统的粘贴只是对文件路径的引用)
1、input文件上传

html部分

<input id="fileInput" type="file" accept="image/png, image/jpeg">
// accept定义支持的文件类型
复制代码

js获取文件

$('#fileInput').on('change', function () {
    fn(this.files[0]);
})
// this.files是一个文件集合,如果一次性上传多个文件相应就是this.files[0]、this.files[1]...
复制代码
2、drop拖放文件上传

html部分可以是一个div元素就行

<div class="dropBox" id="dropHere">
    <p class="info">把文件拖放到这里</p>
    <p class="info hide">你上传的文件是:<span id="fileName"></span></p>
</div>
复制代码

js操作部分需要对目标元素的ondragenter和ondragover进行阻止默认事件操作,防止浏览器直接打开文件

// 拖拽上传事件
function bandDropEvent (el,fn) {
    el.ondragenter = function (event) {   // 清除默认事件,防止浏览器直接打开图片文件
        event.stopPropagation();
        event.preventDefault();
    };
    el.ondragover = function (event) {   // 清除默认事件,防止浏览器直接打开图片文件
        event.stopPropagation();
        event.preventDefault();
    };
    el.ondrop = function (event) {
        event.stopPropagation();
        event.preventDefault();
        fn(event.dataTransfer.files[0]);
    };
}
复制代码

更好的做法是在div里再放一个type='file'的input,然后绑定点击div事件触发input的点击事件,这样就可以同时支持点击及拖放上传


二、图片编辑

解决完文件上传之后,接着就需要对文件数据进行操作啦!首先我们拿图片文件来练手,这里我们分几个步骤:

1、图片预览实现

首先需要了解一个API:FileReader;

FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。 ---来自MDN

直接上代码

function file2url(file, fn) {
    const reader = new FileReader();
    reader.addEventListener('load', function () {
        const src = reader.result;
        fn(src);
    }, false);
    reader.readAsDataURL(file);
}
复制代码
  • 1、首先我们初始化一个 FileReader 的实例 reader ;
  • 2、然后我们监听实例 readerload 事件,将 reader.result 中包含的数据保存到变量 src
  • 3、最后我们调用 reader.readAsDataURL() 方法处理目标文件 file

通过 FileReader.readAsDataURL() 方法,我们可以成功将图片文件转换成一串以 URL格式的字符串 (base64编码)表示所读取文件的内容(FileReader还可以将文件转换成文本格式,此处先不涉及),我们可以将转换后的url赋值给img元素的src属性,这样就可以查看图片预览了

fileInput.addEventListener('change', function () {
    showFileName(this.files[0]);
    file2url(this.files[0], function (src) {
        document.querySelectorAll('img')[0].src = src;
    })
});
复制代码
2、图片编辑

熟悉PS的肯定知道,在位图里整张图片由N多的像素点组成,每一个小的像素点可以想象成一个小的色块,N多色块拼接在一起就成了我们最终看到的图片,如果能操作每个像素点的色值,就能够对图片进行编辑了,我们开始吧:

首先还是一个几个API:(一个个介绍有点长,请自行点击链接去查看相关信息)

  • 1、CanvasRenderingContext2D.drawImage():在canvas上绘制目标图片
  • 2、CanvasRenderingContext2D.getImageData():获取canvas内容的数据
  • 3、CanvasRenderingContext2D.putImageData():将已有的图片数据绘制到canvas

试着用这几个API将图片反色,主要代码如下:

// 将图片反色
function inverse(src) {
    const img = new Image,
        canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');
    let w,h,data;
    img.src = src;
    const imgLoad = new Promise((resolve, reject) => {
        img.onload = function () {
            w = this.width;
            h = this.height;
            canvas.width = w;
            canvas.height = h;
            ctx.drawImage(this, 0, 0, w, h);
            data = ctx.getImageData(0, 0, w, h);
            const obj = {
                data: data,
                width: w,
                height: h
            };
            resolve(obj);
        };
    });
    // 改变图片像素
    imgLoad.then((val) => {
        return new Promise((resolve, reject) => {
            let imgData = val.data.data;
            let w = val.width;
            let h = val.height;
            for(let i = 0; i < h; i++) {        // 遍历像素点
                for(let j = 0; j < w; j++) {
                    let x = i * 4 * w + 4 * j;
                    imgData[x] = 255 - imgData[x];
                    imgData[x + 1] = 255 - imgData[x + 1];
                    imgData[x + 2] = 255 - imgData[x + 2];
                }
            }
            ctx.putImageData(data, 0, 0);
            resolve(canvas.toDataURL("image/jpeg", 1));
        });
    }).then(function (url) {
        document.querySelector('.showNewImg').src = url;
    });
}
复制代码

需要注意的地方:

  • 文件的操作是异步进行的,此处用了Promise;
  • 对像素点的处理用到了嵌套的循环,外层循环X轴,内层循环Y轴上与之交叉的像素点,每一个像素点由4个数据表示,分别对应RGBA;

因此R值的下标为:X轴序号 * 4 * 图片宽度 + Y轴序号 * 4

G值的下标为R值下标+1,B值的下标为R值下标+2,A值的下标为R值下标+3



编辑后的图片文件下载

下载的实现这里用到的是a标签的download属性;

主要代码如下:

function download(url, fileName) {
    const link = document.createElement('a');
    link.href = url;
    link.download = fileName;
    link.click();
}
复制代码


总结

  • 图片的操作还能实现很多其他的效果,贴一个之前写的二维码图片合成页面,这个页面写的比较早,代码有点乱,不过本篇内容出自对该页面的梳理;
  • 接下来还会继续整理,dom转换图片,.html文件编辑等其他文件相关操作;
  • PS:本篇主要对图片的操作做了个简单的总结,代码的实现并没有考虑兼容等(最喜欢写demo这种无拘无束放飞自我的感觉),限于作者能力有限,相关代码仅作示范,如有不足,烦请告知,谢谢