小梅梅的二狗子 小梅梅的二狗子
首页
  • fileReader
  • canvas
  • 【css世界】学习笔记
  • Vue

    • vue cli2 升级vue cli3 采坑记录
    • vue-cli3 项目 token.type.endsWith is not a function 生产事故分析
    • 使用vuepress 搭建团队文档
  • node

    • nodjs 爬取喜欢的的背景图片
    • 使用 puppeteer + nodejs 爬取喜欢的动漫资源
    • puppeteer爬取aspx网站
  • jenkins

    • Jenkins 从安装到自动部署h5
    • vue自动部署项目到服务器
    • jenkins自动打包前端代码并发布到测试或者生产
  • Vscode

    • Visual Studio Code 入门简介 常用插件介绍
    • vscode prettier eslint 插件格式化不生效的问题
  • 其他的

    • 声卡问题
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

qinyuanqi

搬砖使我变强!冲!!!
首页
  • fileReader
  • canvas
  • 【css世界】学习笔记
  • Vue

    • vue cli2 升级vue cli3 采坑记录
    • vue-cli3 项目 token.type.endsWith is not a function 生产事故分析
    • 使用vuepress 搭建团队文档
  • node

    • nodjs 爬取喜欢的的背景图片
    • 使用 puppeteer + nodejs 爬取喜欢的动漫资源
    • puppeteer爬取aspx网站
  • jenkins

    • Jenkins 从安装到自动部署h5
    • vue自动部署项目到服务器
    • jenkins自动打包前端代码并发布到测试或者生产
  • Vscode

    • Visual Studio Code 入门简介 常用插件介绍
    • vscode prettier eslint 插件格式化不生效的问题
  • 其他的

    • 声卡问题
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 前端基础

    • CSS

    • Javascript

      • fileReader
      • canvas
  • 日常采坑

  • 前端框架

  • 部署相关

  • 微信

  • 网易

  • 浏览器

  • 七牛云

  • 前端
  • 前端基础
  • Javascript
qinyuanqi
2023-04-25

fileReader

# fileReader不完全指南

阮一峰的详解 (opens new window)

  • 一个demo 彻底明白fileReader的使用 demo预览 (opens new window)
  • 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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
上次更新: 2023/12/18, 15:00:26
【css世界】学习笔记
canvas

← 【css世界】学习笔记 canvas→

最近更新
01
若依3.8.5版本vue-cli升级到 5.0.8碰到的一些问题
10-08
02
vuepress添加sitemap
05-17
03
vscode Live Server 插件使用教程
05-16
更多文章>
Theme by Vdoing | Copyright © 2019-2023 Evan Xu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式