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学习笔记

  • 相关阅读:
    HDFS、YARN、Mapreduce简介
    List<object> 转 List<T>
    CTR+A组合键 以及终止按键事件传递
    BackgroundWorker 的输入、输出参数、进度条与文字刷新、取消机制、返回事件
    读取Excel文件的两种方法比较 以及用NPOI写入Excel
    浅复制不能传递,重新赋值就重新浅复制
    gridControl添加右键菜单
    C#设置Excel行高、列宽
    任意字符串(包括空串)都包含空白字符串
    JAVA 在程序中存储和修改信息
  • 原文地址:https://www.cnblogs.com/wsmrzx/p/13073355.html
Copyright © 2011-2022 走看看