zoukankan      html  css  js  c++  java
  • JavaScript实战笔记(五) 预览本地图片

    一般情况下,实现本地图片预览有两种方法,一种是 DataURL,一种是 BlobURL

    所以在开始介绍怎么展示本地图片之前,我们花一点时间了解一下什么是 DataURL 和 BlobURL

    1、DataURL

    (1)介绍

    DataURL 就是以 data: 开头的 URL,它将数据编码成特定的格式,并允许开发者在文档中嵌入

    (2)格式

    data:[<mediatype>][;base64],<data>
    
    • data::前缀部分,DataURL 都必须以 data: 开头

    • [<mediatype>]:表明数据的 MIME 类型,可选项,默认为 text/plain;charset=US-ASCII

      MIME 的标准格式是 type/subtype,其中,type 表明数据的分类,subtype 表明具体的类型

      常见的 typesubtype 如下:

      • typetext ,表明数据是普通文本,例如 text/plaintext/html

        在DataURL 中,如果数据是普通文本,还可以在后面用 charset 指定编码,例如 charset=UTF-8

      • typeimage,表明数据是图像类型,例如 image/jpegimage/png

      • typeaudio,表明数据是音频类型,例如 audio/mpegaudio/wav

      • typevideo,表明数据是视频类型,例如 video/webmvideo/ogg

      • typeapplication,表明数据是二进制类型,例如 application/octet-stream

    • [;base64]:可选项,添加后表明后面的数据 <data> 是经过 Base64 编码的

      如果数据是简单文本,那么可以直接嵌入,不需要经过 Base64 编码,因此可以省略

      如果数据是其它类型,那么必须加上 ;base64,并在后面嵌入以 Base64 编码的数据

    • <data>:实际的数据,可以是普通文本,可以是经过 Base64 编码的数据

      如果是经过 Base64 编码的数据,那么前面必须要有 ;base64

    (3)例子

    • 普通文本
    // 不指定文本编码,显示乱码:浣犲ソ
    data:text/plain,你好
    
    // 指定文本编码为 UTF-8,显示正确:你好
    data:text/plain;charset=UTF-8,你好
    
    // 指定文本编码为 UTF-8,并使用 Base64 编码数据,显示正确:你好
    data:text/plain;charset=UTF-8;base64,5L2g5aW9
    
    • 其它类型,例如图片
    data:image/jpeg;base64,iVBORw0KGgoAAAANSUhE...
    

    2、Base64

    (1)介绍

    Base64 是一种基于二进制的编码协议

    它的主要目的是用六十四个可打印字符表示所有数据(包括中文、二进制等)

    在默认情况下,这六十四个可打印字符包括 [A-Z|a-z|0-9|+|/]

    (2)原理

    Base64 的编码过程很简单,下面我们直接用一个例子来进行讲解

    原数据:Hello,原数据二进制:01001000 01100101 01101100 01101100 01101111
    
    1、将原数据,每 3 个字节分为 1 组,这样就能得到多组 24 个二进制位
    
    (01001000 01100101 01101100) (01101100 01101111)
    
    如果不足 24 个二进制位,后面会讲如何处理
    
    2、将每组 24 个二进制位,每 6 个二进制位分为 1 个小组,这样每个大组包含 4 个小组
    
    (010010 000110 010101 101100) (011011 000110 1111)
    
    如果不足 6 个二进制位,后面补 0;如果不足一组 6 个二进制位,用 = 代替
    
    (010010 000110 010101 101100) (011011 000110 111100 =)
    
    3、对每组 6 个二进制位,在前面添加两个二进制位 00,这样每个大组包含 4 个字节
       
    (00010010 00000110 00010101 00101100) (00011011 00000110 00111100 =)
    
    4、最后对照编码表,查询每个字节对应的编码,就能得到原数据的 Base64 编码
    
    SGVsbG8=
    
    实际上编码表也很简单,如下:
    
    二进制字节 00000000 ~ 00011001 对应编码 A ~ Z
    二进制字节 00011010 ~ 00110011 对应编码 a ~ z
    二进制字节 00110100 ~ 00111101 对应编码 0 ~ 9
    二进制字节 00111110 对应编码 +
    二进制字节 00111111 对应编码 /
    

    (3)应用

    Web API 中有编码和解码 Base64 数据的方法,分别是 btoa()atob()

    • btoa():编码,对数据进行 Base64 编码
    • atob():解码,对经过 Base64 编码后的数据解码
    let originalStr = 'Hello'
    let encodedData = window.btoa(originalStr)
    let decodedData = window.atob(encodedData)
    
    console.log(encodedData) // SGVsbG8=
    console.log(decodedData) // Hello
    

    3、Blob

    (1)Blob

    Blob 对象表示一个不可变、原始数据的类文件对象(常用于表示二进制数据),它的构造函数如下:

    Blob(array, options)
    
    • array:一个由 ArrayBufferBlobDOMString 等对象构成的 Array
    • options:对象类型,包含一些可选属性,包括
      • type:表示 MIME 类型,默认为 ""
      • endings:指定包含行结束符 的字符串如何被写入,默认为 transparent

    Blob 对象具有以下属性和方法:

    • size:只读属性,表示数据的大小
    • type:只读属性,表示数据的 MIME 类型
    • text():返回一个 Promise,包含 Blob 所有内容的 UTF-8 格式的 USVString
    • arrayBuffer():返回一个 Promise,包含 Blob 所有内容的 Binary 格式的 ArrayBuffer

    (2)File

    File 对象是一个特殊的 Blob,我们通常会在用 <input> 标签上传文件的场景遇到这个对象

    它保存着文件的描述信息以及文件的原始数据,除了继承 Blob 的属性外,File 还具有以下的属性:

    • size:只读属性,表示数据的大小
    • type:只读属性,表示数据的 MIME 类型
    • name:只读属性,表示文件的名称
    • lastModified:只读属性,表示文件的最后修改时间,自 UNIX 时间起始值以来的毫秒数
    • lastModifiedDate:只读属性,表示文件的最后修改时间,Date 对象

    4、BlobURL

    可以用 URL.createObjectURL() 给 Blob 等对象创建一个 URL,之后通过这个 URL 可以访问原始数据

    但是需要注意的是,这些 URL 对象是不会自动释放的,只有当 document 卸载时才会同时释放这些对象

    当然我们还有更好的选择,那就是当我们不再需要这些对象时,通过 URL.revokeObjectURL() 主动释放

    5、DataURL 与 Blob 的转化

    (1)DataURL -> Blob

    function dataURLtoBlob(dataURL) {
        return new Promise((resolve, reject) => {
            let [descString, dataString] = dataURL.split(',')
            let mimeType = descString.split('data:')[1].split(';base64')[0]
            let byteData = window
            	? window.atob(dataString)
            	: Buffer.from(dataString, 'base64').toString('binary')
            let intArray = new Uint8Array(new ArrayBuffer(byteData.length))
            for (let idx = 0; idx < byteData.length; idx++) {
                intArray[idx] = byteData.charCodeAt(idx)
            }
            let blob = new Blob([intArray], {type: mimeType})
            resolve(blob)
        })
    }
    

    (2)Blob -> DataURL

    function blobToDataURL(blob) {
        return new Promise((resolve, reject) => {
            blob.arrayBuffer().then((arrayBuffer) => {
                let mimetype = blob.type
                let intArray = new Uint8Array(arrayBuffer)
                let byteData = [].map.call(intArray, (val) => {
                    return String.fromCharCode(val)
                }).join('')
                let dataString = window
                    ? window.btoa(byteData)
                    : Buffer.from(byteData).toString('base64')
                let descString = 'data:' + mimetype + ';base64'
                let dataURL = descString + ',' + dataString
                resolve(dataURL)
            })
        })
    }
    

    注意,在上面的解决方案中,blob.arrayBuffer() 的兼容性其实并不是很好

    事实上,我们有一个更加简单的解决方案

    function blobToDataURL(blob) {
        return new Promise((resolve, reject) => {
            let reader = new FileReader()
            reader.onloadend = function() {
                resolve(reader.result)
            }
            reader.readAsDataURL(blob)
        })
    }
    

    6、图片预览

    (1)BlobURL

    <!DOCTYPE html>
    <html>
    <head>
        <script>
            function bindEvent() {
                const input = document.querySelector('input[type=file]')
                input.addEventListener('change', uoloadFile)
            }
    
            function uoloadFile(e) {
                let files = e.target.files;
                if (files.length > 0) {
                    let file = files[0]
                    document.querySelector('#avatar').src = URL.createObjectURL(file)
                }
            }
        </script>
    </head>
    
    <body onload="bindEvent()">
        <input type="file" accept="image/png, image/jpeg" />
        <image id="avatar" />
    </body>
    
    </html>
    

    (2)DataURL

    <!DOCTYPE html>
    <html>
    <head>
        <script>
            function bindEvent() {
                const input = document.querySelector('input[type=file]')
                input.addEventListener('change', uoloadFile)
            }
    
            function uoloadFile(e) {
                let files = e.target.files;
                if (files.length > 0) {
                    let file = files[0]
                    blobToDataURL(file).then((dataURL) => {
                        document.querySelector('#avatar').src = dataURL
                    })
                }
            }
    
            function blobToDataURL(blob) {
                return new Promise((resolve, reject) => {
                    let reader = new FileReader()
                    reader.onloadend = function() {
                        resolve(reader.result)
                    }
                    reader.readAsDataURL(blob)
                })
            }
        </script>
    </head>
    <body onload="bindEvent()">
        <input type="file" accept="image/png, image/jpeg" />
        <image id="avatar" />
    </body>
    </html>
    

    (3)实现效果

    【 阅读更多 JavaScript 系列文章,请看 JavaScript学习笔记

  • 相关阅读:
    366. Find Leaves of Binary Tree输出层数相同的叶子节点
    716. Max Stack实现一个最大stack
    515. Find Largest Value in Each Tree Row查找一行中的最大值
    364. Nested List Weight Sum II 大小反向的括号加权求和
    156. Binary Tree Upside Down反转二叉树
    698. Partition to K Equal Sum Subsets 数组分成和相同的k组
    244. Shortest Word Distance II 实现数组中的最短距离单词
    187. Repeated DNA Sequences重复的DNA子串序列
    java之hibernate之基于主键的双向一对一关联映射
    java之hibernate之基于主键的单向一对一关联映射
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/13073355.html
Copyright © 2011-2022 走看看