前端blob数据

Blob介绍

定义

Blob 对象表示一个不可变原始数据类文件对象。它的数据可以按文本二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。 通常可以用于声音、视频等多媒体文件的存储;

构造
new Blob(blobParts, options);

blobParts:数组类型,可以存放任意个ArrayBufferArrayBufferViewBlobDOMString(会编码为utf-8);
options:可选,可以设置blob的typeendings

  • type:blob中数组元素的MIME类型,默认为'';
  • endings:包含行字符串\n的字符串如何被写入。默认值_transparent_保留不变,_native_会改为对应宿主操作系统文件系统的换行符。

DOMString 是一个UTF-16字符串。由于JavaScript已经使用了这样的字符串,所以DOMString直接映射到 一个String。

在这里插入图片描述

属性

type:返回blob的MIME类型
size:blob的数据大小(字节)

方法
返回一个新的 Blob 对象,包含了源 Blob 对象中指定范围内的数据。
Blob.slice([start[, end[, contentType]]])

// 返回一个能读取blob内容的 ReadableStream。
Blob.stream();

// 返回一个promise且包含blob所有内容的UTF-8格式的 USVString。
Blob.text()

// 返回一个promise且包含blob所有内容的二进制格式的 ArrayBuffer 
Blob.arrayBuffer()
从Blob总提取数据

可以使用FileReader对象

const reader = new FileReader();
reader.addEventListener('loaded', function() {
	// reader.reasult 包含被转换为typedArray的Blob
});

reader.readAsArrayBuffer(blob);

可以使用Response对象

const text = await (new Response(blob)).text()

在这里插入图片描述

File对象

定义

通常情况下, File 对象是来自用户在一个 <input> 元素上选择文件后返回的 FileList 对象,也可以是来自由拖放操作生成的 DataTransfer 对象,或者来自 HTMLCanvasElement 上的 mozGetAsFile() API

属性

name:文件名
size:文件大小
lastModified:文件最后修改时间对应时间戳
type:MIME类型
webkitRelativePath:返回file相关的path和URL

方法

slice:继承了Blob的slice方法

demo

<input>元素

    <input type="file" id="fileUploader" multiple accept="image">
        <script>
        const el = document.getElementById('fileUploader');
        el.onchange = (e) => {
            const files = e.target.files;
            console.log({ files }, files[0])
        }
    </script>
<div id="fileUploader"
	ondrop="drop(e)"
	ondragover="allowDrop(e)"
></div>
<script>
	function drop(e) {
		e.preventDefault();
		const files = e.dataTransfer.files;
		console.log({ files });
		console.log(files instanceof FileList);
	}
	
	function allowDrop(e) {
		e.preventDefault();
	}

	
</script>

在这里插入图片描述

数据缓冲区

定义

数据缓冲区指的是内存中操作二进制数据的一片连续的存储区,相对于数组可以有效提高数据读取效率;

在这里插入图片描述

Buffer

BufferNode提供的对象,可以通过Buffer创建存储二进制数据的缓冲区用于整合前端媒体文件数据 等;

一个Buffer类似于一个整数数组,但它对应于V8堆内存之外的一块原始内存

ArrayBuffer

表示一段固定长度的连续的用于存储二进制数据的缓存区;对于高密度访问的数据(音视频数据等)读取效率更高,因为数据会提前写入到内存中;
在这里插入图片描述
在这里插入图片描述

属性——byteLength,表示ArrayBuffer的大小
方法——slice(start, end),返回一个新的ArrayBuffer

ArrayBufferView

ArrayBuffer未提供任何直接读写内存的方法,而ArrayBufferView是建立在ArrayBuffer上的视图,提供了处理二进制数据的基本单元,可以读取ArrayBuffer的内容;

TypedArraysDataView是ArrayBufferView的实例

FileReader

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

重要提示:FileReader 仅用于以安全的方式从用户(远程)系统读取文件内容 它不能用于从文件系统中按路径名简单地读取文件。要在 JavaScript 中按路径名读取文件,应使用标准 Ajax 解决方案进行服务器端文件读取,如果读取跨域,则使用 CORS 权限。

  • readAsText(Blob):将Blob转化为文本字符串
  • readAsArrayBuffer(Blob):将Blob转为ArrayBuffer格式数据
  • readAsDataURL(): 将Blob转化为Base64格式的DataURL

以下demo通过FileReader展示上传的图片

<!DOCTYPE html>
<html class="no-js">
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<title></title>
		<meta name="description" content="" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<link rel="stylesheet" href="" />
	</head>
 
	<body>
		<input type="file" multiple id="myFile" />
		<input type="file" multiple id="myFile2" />
        <div id="previewer"></div>
		<script type="text/javascript">
			if (window.FileReader) {
				var reader = new FileReader();
			} else {
				console.log('你的浏览器不支持读取文件');
			}
			var myFile = document.querySelector('#myFile');
			myFile.onchange = function () {
				var file = myFile.files[0];
				reader.readAsDataURL(file);
				reader.onload = function () {
					var data = reader.result;   //base64形式的文件内容
                    console.log('data: ', data);
                    const img = new Image();
                    img.src = data;
                    document.querySelector('#previewer').appendChild(img);
				};
                reader.onerror = function(){
                    console.log('读取失败');
                    console.log(reader.error);
                }
			};

            // blobUrl(objectUrl)
            var myFile2 = document.querySelector('#myFile2');

            myFile2.onchange = function (event) {
                const file = event.target.files[0];

                const img = document.createElement('img');
                img.src = window.URL.createObjectURL(file); // window.createObjectURL(file) || window.URL.createObjectURL(file) || window.webkitURL.createObjectURL(file)
                document.querySelector('#previewer').appendChild(img);

            }
		</script>
	</body>
</html>

以下demo通过FileReader读取一个text文本文件内容:

<!DOCTYPE html>
<html class="no-js">
	<head>
		<meta charset="utf-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<title></title>
		<meta name="description" content="" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<link rel="stylesheet" href="" />
	</head>
 
	<body>
		<input type="file" multiple id="myFile" />
		<input type="file" multiple id="myFile2" />
		<input type="file" multiple id="textFile" />
        <div id="previewer"></div>
		<script type="text/javascript">
            // reader.readerAsText(file)
            const myFile3 = document.querySelector('#textFile');
            const textReader = new FileReader();

            myFile3.onchange = function (event) {
                const file = event.target.files[0];

                textReader.onload = function () {
                    const content = textReader.result;
                    console.log('text content: ', content);
                }

                textReader.readAsText(file);
            }


		</script>
	</body>
</html>

在这里插入图片描述

BlobURL

**BlobURL(ObjectURL)**是一种伪协议,只能由浏览器在内部生成,我们知道script/img/video/iframe等标签的src属性和background的url可以通过url和base64来显示,我们同样可以把blob或者file转换为url生成BlobURL来展示图像,BlobURL允许Blob和File对象用作图像,下载二进制数据链接等的URL源。

图像展示

具体代码见上面demo

在这里插入图片描述

文档下载

<!DOCTYPE html>
<html class="no-js">

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title></title>
    <meta name="description" content="" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="" />
</head>

<body>
    <input type="file" multiple id="myFile" />
    <input type="file" multiple id="myFile2" />
    <input type="file" multiple id="textFile" />
    <button onclick="download()">下载</button>
    <div id="previewer"></div>
    <script type="text/javascript">
        if (window.FileReader) {
            var reader = new FileReader();
        } else {
            console.log('你的浏览器不支持读取文件');
        }

        const getObjectURL = (file) => {
            let url;
            if (window.createObjectURL) {
                url = window.createObjectURL(file);
            } else if (window.URL) {
                url = window.URL.createObjectURL(file);
            } else if (window.webkitURL) {
                url = window.webkitURL.createObjectURL(file);
            }
            return url;
        };

        var myFile = document.querySelector('#myFile');
        myFile.onchange = function () {
            var file = myFile.files[0];
            reader.readAsDataURL(file);
            reader.onload = function () {
                var data = reader.result; //base64形式的文件内容
                console.log('data: ', data);
                const img = new Image();
                img.src = data;
                document.querySelector('#previewer').appendChild(img);
            };
            reader.onerror = function () {
                console.log('读取失败');
                console.log(reader.error);
            }
        };

        // blobUrl(objectUrl)
        var myFile2 = document.querySelector('#myFile2');

        myFile2.onchange = function (event) {
            const file = event.target.files[0];

            const img = document.createElement('img');
            img.src = window.URL.createObjectURL(file); // window.createObjectURL(file) || window.URL.createObjectURL(file) || window.webkitURL.createObjectURL(file)
            document.querySelector('#previewer').appendChild(img);

        }

        // reader.readerAsText(file)
        const myFile3 = document.querySelector('#textFile');
        const textReader = new FileReader();

        myFile3.onchange = function (event) {
            const file = event.target.files[0];

            textReader.onload = function () {
                const content = textReader.result;
                console.log('text content: ', content);
            }

            textReader.readAsText(file);

        }


        // file download
        function download() {
            const fileName = 'download.txt';
            const myBlob = new Blob(['BlobURL download text file'], { type: 'text/plain' });

            downloadFn(fileName, myBlob);
        }

        function downloadFn(fileName, blob) {
            const link = document.createElement('a');
            link.href = getObjectURL(blob);
            link.download = fileName;
            link.click();
            link.remove();
            URL.revokeObjectURL(link.href); // 不再使用的BlobUrl后续会自动清除(关闭浏览器也会自动清除),但是最好使用URL.revokeObjectURL(url)手动清除它们
        }

    </script>
</body>

</html>

dataURL

dataURL允许内容的创建者将较小的文件嵌入到文档中。与常规的URL使用场合类似

用法:

data:[<mediatype>][;base64],data
  • data: 固定前缀
  • mediatype: 表明数据类型,是一个_MIME_类型字符串,如image/jpeg表示一个JPEG图片文件。如果省略,默认值为_text/plain;charset=US-ASCII_。
  • base64: 标志位(如果是文本,则可选)
  • data: 数据本身

如何获取dataURL

在这里插入图片描述

Javascript中有两个函数负责编码和解码base64字符串,分别是atob和btoa。两者都只针对Data URL中的data进行处理。

dataURL使用

  • 当图片的体积太小,占用一个HTTP会话不是很值得时。
  • 当访问外部资源很麻烦或受限时
  • DataUrl不会被浏览器缓存,但是小部分会通过css缓存,在下面例子中,DataUrl的使用是完全符合场
  • 作为下载连接使用

dataURL vs BlobURL

在这里插入图片描述

数据格式转换

在这里插入图片描述

应用场景

图像灰度化

这里主要用到canvasimageData的转换

<!DOCTYPE html>
<html class="no-js">

<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <title></title>
    <meta name="description" content="" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <link rel="stylesheet" href="" />
    <style>
        .imgPreviewer {
            display: flex;
        }
    </style>
</head>

<body>
    <input type="file" multiple id="myFile" />
    <input type="file" multiple id="myFile2" />
    <input type="file" multiple id="textFile" />
    <button onclick="download()">下载</button>
    <input type="file" id="grayImage" />
    <div id="previewer"></div>
    <div class="imgPreviewer">
        <canvas id="original"></canvas>
        <canvas id="gray"></canvas>
    </div>
    <script type="text/javascript">
        if (window.FileReader) {
            var reader = new FileReader();
        } else {
            console.log('你的浏览器不支持读取文件');
        }

        const getObjectURL = (file) => {
            let url;
            if (window.createObjectURL) {
                url = window.createObjectURL(file);
            } else if (window.URL) {
                url = window.URL.createObjectURL(file);
            } else if (window.webkitURL) {
                url = window.webkitURL.createObjectURL(file);
            }
            return url;
        };

        var myFile = document.querySelector('#myFile');
        myFile.onchange = function () {
            var file = myFile.files[0];
            reader.readAsDataURL(file);
            reader.onload = function () {
                var data = reader.result; //base64形式的文件内容
                console.log('data: ', data);
                const img = new Image();
                img.src = data;
                document.querySelector('#previewer').appendChild(img);
            };
            reader.onerror = function () {
                console.log('读取失败');
                console.log(reader.error);
            }
        };

        // blobUrl(objectUrl)
        var myFile2 = document.querySelector('#myFile2');

        myFile2.onchange = function (event) {
            const file = event.target.files[0];

            const img = document.createElement('img');
            img.src = window.URL.createObjectURL(file); // window.createObjectURL(file) || window.URL.createObjectURL(file) || window.webkitURL.createObjectURL(file)
            document.querySelector('#previewer').appendChild(img);

        }

        // reader.readerAsText(file)
        const myFile3 = document.querySelector('#textFile');
        const textReader = new FileReader();

        myFile3.onchange = function (event) {
            const file = event.target.files[0];

            textReader.onload = function () {
                const content = textReader.result;
                console.log('text content: ', content);
            }

            textReader.readAsText(file);

        }


        // file download
        function download() {
            const fileName = 'download.txt';
            const myBlob = new Blob(['BlobURL download text file'], { type: 'text/plain' });

            downloadFn(fileName, myBlob);
        }

        function downloadFn(fileName, blob) {
            const link = document.createElement('a');
            link.href = getObjectURL(blob);
            link.download = fileName;
            link.click();
            link.remove();
            URL.revokeObjectURL(link.href); // 不再使用的BlobUrl后续会自动清除(关闭浏览器也会自动清除),但是最好使用URL.revokeObjectURL(url)手动清除它们
        }


        // 图像灰度化
        const colorfulImageReader = document.querySelector('#grayImage');
        const imgReader = new FileReader();



        colorfulImageReader.onchange = (event) => {
            const file = event.target.files[0];

            imgReader.readAsDataURL(file);

            imgReader.onload = () => {
                const result = imgReader.result;
                const img = document.createElement('img');
                img.src = result;
                img.width = 300;
                img.height = 440;
                document.querySelector('#previewer').appendChild(img);


                console.log('images: ', img, img.width, img.height)

                img.onload = () => {
                    const canvas = document.getElementById('original');

                    const context = canvas.getContext('2d');

                    canvas.width = img.width;

                    canvas.height = img.height;

                    context.drawImage(img, 0, 0, img.width, img.height);

                    var imageData, data, i, len, average, red, green, blue;

                    imgData = context.getImageData(0, 0, img.width, img.height);

                    data = imgData.data;



                    for (i = 0, len = data.length; i < len; i += 4) {
                        red = data[i];
                        green = data[i + 1];
                        blue = data[i + 2];
                        // alpha = data[i + 3];

                        average = Math.floor((red + green + blue) / 3);

                        data[i] = average;
                        data[i + 1] = average;
                        data[i + 2] = average;
                    }


                    imgData.data = data;

                    const myCanvas = document.getElementById('gray');
                    myCanvas.width = img.width;
                    myCanvas.height = img.height;
                    const myContext = myCanvas.getContext('2d');

                    myContext.putImageData(imgData, 0, 0, 0, 0, img.width, img.height);
                }
            }

        }



    </script>
</body>

</html>


图片压缩

A Number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression (such as image/jpeg or image/webp). A user agent will use its default quality value if this option is not specified, or if the number is outside the allowed range.

toDataURL(type, encoderOptions)第二个参数可以用于控制图片质量,可以用此参数实现图片压缩

// compress.js

const MAX_WIDTH = 800; // 图片最大宽度

function compress(base64, quality, mimeType) {
  let canvas = document.createElement('canvas');
  let img = document.createElement('img');
  img.crossOrigin = 'anonymous';
  return new Promise((resolve, reject) => {
    img.src = base64;
    img.onload = () => {
      let targetWidth, targetHeight;
      if (img.width > MAX_WIDTH) {
        targetWidth = MAX_WIDTH;
        targetHeight = (img.height * MAX_WIDTH) / img.width;
      } else {
        targetWidth = img.width;
        targetHeight = img.height;
      }
      canvas.width = targetWidth;
      canvas.height = targetHeight;
      let ctx = canvas.getContext('2d');
      ctx.clearRect(0, 0, targetWidth, targetHeight); // 清除画布
      ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
      // 通过toDataURL压缩后的base64
      let imageData = canvas.toDataURL(mimeType, quality / 100);
      resolve(imageData);
    };
  });
}
<body>
    <input type="file" accept="image/*" onchange="loadFile(event)" />
    <script src="./compress.js"></script>
    <script>
      function dataUrlToBlob(base64) {
        var arr = base64.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);

        while (n--) {
          u8arr[n] = bstr.charCodeAt(n);
        }
        return new Blob([u8arr], { type: mime });
      }

      function uploadFile(url, blob) {
        let formData = new FormData();
        let request = new XMLHttpRequest();
        // 封装到FormData中进行文件的上传
        formData.append('image', blob);
        request.open('POST', url, true);
        request.send(formData);
      }

      const loadFile = function (event) {
        const reader = new FileReader();
        reader.onload = async function () {
          let compressedDataURL = await compress(reader.result, 90, 'image/jpeg');
          // 压缩后将base64转为Blob 对象减少传输数据量
          let compressedImageBlob = dataUrlToBlob(compressedDataURL);
          uploadFile('https://httpbin.org/post', compressedImageBlob);
        };
        // 获取用户选取的图片文件,通过FileReader转化成base64
        reader.readAsDataURL(event.target.files[0]);
      };
    </script>
  </body>

参考文献

  1. Blob 对象表示一个不可变、原始数据的类文件对象。它的数据可以按文本或二进制的格式进行读取,也可以转换成 ReadableStream 来用于数据操作。
  2. 「多图预警」那些年,被blob虐过的程序猿觉醒了!
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Neil-

你们的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值