前端二进制-实战
Posted lin-fighting
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了前端二进制-实战相关的知识,希望对你有一定的参考价值。
二进制对象
ArrayBuffer
TypedArray
DataView
Blob
Object Url
ArrayBuffer
- ArrayBuffer对象用来表示通用的,固定长度的原始二进制缓冲区。
- 他是一个字节数组,通常在其它语言中称为byte array
- 不能直接操作ArrayBuffer的内容,而是要通过类型数组对象(TypedArray)或者DataView对象来操作。他们会将缓区中的数据表示为特定的格式,并通过这些格式来读取内容。
const buffer = new ArrayBuffer(8) // 8个字节,64位
console.log(buffer.byteLength);不能直接操做
操作ArrayBuffer的对象
TypedArray, DataView
TypedArray
- TypedArray对象描述了一个底层的二进制缓存区的一个类数组视图
- 它本身无法被实例化,甚至无法访问,可以把他理解为接口,他有很多的实现。
- Int8Array 8位二进制有符号整数 -128 - 127 每单位1个bit
- Unit7Array 8位无符号整数 0-255 每单位1个bit
- Int16Array 16位二进制有符号整数 -32768 - 32767 每单位2个bit
- Unit16Array 16位无符号整数 0 - 65535 每单位2个bit
const buffer = new ArrayBuffer(8)
const int8Array = new Int8Array(buffer)
const int16Array = new Int16Array(buffer)
console.log(int8Array .buffer);
console.log(int8Array.length);
console.log(int16Array.length);
//
8 8 4
因为Int16Array每个单位是两个字节,所以八个字节就有四个单位,所以长度是4
ArrayBuffer无法直接操作,可以通过Int8Array等类来操作。
DataView(任意读取多种数值类型)
- DataView视图是一个可以从二进制ArrayBuffer对象中读写多种数值类型的底层接口
- setInt8()从DataView起始位置以byte为计数的指定偏移量(byteOffset)处存储了一共8-bit数
- getInt8()从DataView起始位置以byte为计数的指定偏移量(byteOffset)处获取了一共8-bit数
const buffer = new ArrayBuffer(2) //设置一个2字节的二进制对象
const dataView = new DataView(buffer)
console.log(dataView.buffer)
dataView.setInt8(0, 2) //从0开始,设置了一个值为2,结果应该是
dataView.setInt8(1,3) //从1个字节开始,设置了3
console.log(dataView.getInt8(0)); //2
console.log(dataView.getInt8(1)); // 3
console.log(dataView.getInt16(0)); // 515
//因为
2是 00000010
3是 00000011
结合起来就是 00000010 00000011 这样一个二进制数就是515
三者关系
DataView => dataView.buffer => ArrayBuffer
ArrayBuffer => new DataView(buffer) => DataView
TypedArray => new TypedArray(buffer) =>ArrayBuffer
ArryaBuffer => typedArray.buffer => TypedArray
Blob
- Blob对象表示一个不可变的,原始数据类型的类文件对象,Blob表示的不一定是js原生格式的数据,
- Fibe接口基于Blob,继承了Blob的功能并将其扩展使其支持用
const debug = name: '123'
let str = JSON.stringify(debug)
const blob = new Blob([str],type: 'application/json')
console.log(blob);
//
size: 14
type: "application/json"
// 转换ArrayBuffer
const blob = new Blob([buffer],type: 'application/json')
console.log(blob);
size: 2
type: "application/json"
- Blob()构造函数返会一个新的Blob对象,Blob的内容由参数数组中给出的值串联组成。
- FileReader对象允许Web应用程序异步读取存储在用户计算机上的文件的内容。使用File或者Blob对象指定要读取的文件或数据。
- readAsText()读取文本文件,返回文本字符串,默认编码使utf-8
- readAsDataURL():读取文本获取一段以data开头的字符串,这段字符串的本质就是DataURL,DataURL是一种将文件嵌入到文档的方案,DataURL使将资源转为base64编码的字符串形式,并将这些内容存储到url中。
- 一个blob对象可以被读取成多个类型。
- 构造函数 const blob = new Blob(array,options)
- array可以是一个由ArrayBuffer,ArrayBufferView,Blob,DomString等对象构成的Array,或者其他类似对象的混合体,它将会被放入Blob,DOMstring会被编写成utf-8
- options是一个可选的BlobPropertyBag字典,type默认值是’’,他代表了将会被放入到blob中的数组内容的MIME类型。
- 例子:
const buffer = new ArrayBuffer(2); //设置一个2字节的二进制对象
const blob = new Blob([buffer], type: "application/json" );
console.log(blob);
//一个blob可以被读成多个类型
function readBlob(blob, type)
return new Promise(function (resolve)
// fileReader可以读取存储在用户计算机的文件的内容。
const reader = new FileReader();
reader.onload = (e) =>
resolve(e.target?.result);
;
switch (type)
case "ArrayBuffer":
reader.readAsArrayBuffer(blob);
break;
case "DataURL": // 二进制数据转为base64
reader.readAsDataURL(blob);
break;
case "Text":
reader.readAsText(blob, "utf-8");
break;
default:
break;
);
readBlob(blob, "ArrayBuffer").then((res) =>
console.log(res);
);
readBlob(blob, "DataURL").then((res) =>
console.log(res);
);
readBlob(blob, "Text").then((res) =>
console.log(res);
);
//
Blob size: 2, type: 'application/json'
ArrayBuffer(2) // ArrayBuffer类型
data:application/json;base64,AAA= //DataURL类型
空字符串 //Text类型
总结
FIleReader可以读取File或者Blob对象,将其转换成对应的数据,如DataUrl, ArrayBuffer和text等等。
比如input上传的图片是Blob对象,可以通过FileReader转为DataUrl,然后给img标签使用就可以。
// react
const [imgUrl, setImgUrl] = useState<string>();
const onInputChnge = (e: React.ChangeEvent<htmlInputElement>) =>
const file = e.target.files ? e.target.files[0] : null; //input上传的图片是Blob对象
console.log(file instanceof Blob);
const fileReader = new FileReader();
fileReader.readAsDataURL(file!); //转为地址
fileReader.onload = (e) =>
console.log(e.target?.result);
setImgUrl(e.target?.result as string);
;
;
// html
<input type="file" accept="image/*" onChange=onInputChnge />
<img src=imgUrl alt="" />
Object URL
- 可以使用浏览器新的API URL对象通过一个方法生成一个地址来表示Blob数据。
- 格式为 blob:< origin >/< uuid >
- URL.creatObjectURL静态方法会创建一个DOMString,其中包含一个表示参数中给出的对象的URL,这个URL的生命周期喝创建他的窗口中的document绑定。
- URL对象表示指定的FIle对象或者Blob对象。
- revokeObjectURL静态方法用来释放一个值存在的,通过调用URL.createObjectURL()创建的URL对象。
如
<button onclick="download()">下载</button>
<script>
const debug = name: '123'
let str = JSON.stringify(debug)
const blob = new Blob([str],type: 'application/json')
console.log(blob);
function download()
const a = document.createElement('a')
a.download = 'user.json'
a.rel = 'noopener'
a.href = URL.createObjectURL(blob)
console.log(a);
//<a download="user.json" rel="noopener" href="blob:null/b0ffdc55-b049-492c-ad92-ac667b27d3ba"></a>
// 触发a的点击事件
a.dispatchEvent(new MouseEvent('click'))
URL.revokeObjectURL(blob) //用于垃圾回收,销毁
</script>
通过Object.createObjectUrl将blob对象转为一个地址,可以看到href返回了一个以blob:开头的地址,
打开浏览器,点击下载之后,下载了一个文件。
user.json
"name":"123"
Blob对象通过Url.createObjectURL创建了url,可以给image使用。
Canvas & DataURl & imageData & Blob/FIle
File类型转为DataUrl,再转为Canvas可以使用的,再截取canvas的数据,通过Canvas.toDataURL()转为DataUrl,最后再转为blob对象,可以上传服务器。
FIle转为DataUrl,借助FileReader
// 通过input事件
const onInputChnge = (e: React.ChangeEvent<HTMLInputElement>) =>
setlastPosition( startX: 0, startY: 0 );
setPosition( startX: 0, startY: 0 );
const file = e.target.files ? e.target.files[0] : null; //input上传的图片是Blob对象
console.log(file instanceof Blob);
const fileReader = new FileReader();
fileReader.readAsDataURL(file!); //转为地址
fileReader.onload = (e) =>
console.log(e.target?.result); // 这就是转化后的url
setImgUrl(e.target?.result as string);
;
;
//将图片绘制到canvas
// 将图片绘制到canvas
const drawImage = (scale1: any = 1, left = 0, top = 0) =>
if (imgRef.current && canvasRef.current)
const image = imgRef.current;
let canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
// 清掉canvas
ctx?.clearRect(0, 0, canvas.width, canvas.height);
//
let imageWidht = image.width;
let imageHieght = image.height;
if (imageWidht > imageHieght)
let scale = canvas.width / imageWidht;
imageWidht = canvas.width;
imageHieght = imageHieght * scale;
else
let scale = canvas.height / imageHieght;
imageHieght = canvas.height;
imageWidht = imageWidht * scale;
requestAnimationFrame(() =>
ctx?.drawImage(
image, // Img元素
(300 - imageWidht) / 2 + left,
(300 - imageHieght) / 2 + top,
imageWidht,
imageHieght
);
);
;
直接通过ctx.drwaImage将元素传进去就行。
canvas数据转为DataUrl
// 截图, canvas数据可以通过toDataURL转为url
const confirm = (e) =>
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
// 截取,xy坐标+宽高
const imageData = ctx?.getImageData(100, 100, 100, 100);
const avatarCanvas = document.createElement("canvas");
avatarCanvas.width = 100;
avatarCanvas.height = 100;
const avatrCtx = avatarCanvas.getContext("2d");
avatrCtx?.putImageData(imageData!, 0, 0);
const dataURl = (avatarCanvas as any).toDataURL(); //转为url ,这个是关键
setImgUrl1(dataURl);
;
DataUrl转为Blob对象供上传
通过window.atob转化,然后通过ArrayBuffer和uInt8Array转化。
// 转为blob对象可供上传
// atob()用于解码 base64编码的字符串
// btoa()//将字符串编码成base64字符串
const onUpload = (event) =>
const bytes: string = window.atob(imgUrl1!.split(",")[1]);
const arrayBuffer = new ArrayBuffer(bytes.length); //创建一个长度一样大的buffer数组
const uInt8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < bytes.length; i++)
uInt8Array[i] = bytes.charCodeAt[i];
const blob = new Blob([arrayBuffer], type: "image/png" ); // 转为blob对象
console.log("blob", blob);
// 通过FileReader又将blob转为DataUrl
const fileReader = new FileReader();
fileReader.readAsDataURL(blob!); //转为地址
fileReader.onload = (e) =>
console.log(e.target?.result);
setImgUrl2(e.target?.result as string);
;
;
这里实现的是一个上传图片并且截图头像的功能。所有代码如下,因demo,所以没有整理,随便写了下:
import React, useState from "react";
import ReactDOM from "react-dom";
import "core-js/stable";
import "regenerator-runtime/runtime";
import useSetRem from "./utils";
import "./assets/css/init.less";
import Button from "antd";
// const buffer = new ArrayBuffer(2); //设置一个2字节的二进制对象
// const blob = new Blob([buffer], type: "application/json" );
// console.log(blob);
// //一个blob可以被读成多个类型
// function readBlob(blob, type)
// return new Promise(function (resolve)
// const reader = new FileReader();
// reader.onload = (e) =>
// resolve(e.target?.result);
// ;
// switch (type)
// case "ArrayBuffer":
// reader.readAsArrayBuffer(blob);
// break;
// case "DataURL": // 二进制数据转为base64
// reader.readAsDataURL(blob);
// break;
// case "Text":
// reader.readAsText(blob, "utf-8");
// break;
// default:
// break;
//
// );
//
// readBlob(blob, "ArrayBuffer").then((res) =>
// console.log(res);
// );
// readBlob(blob, "DataURL").then((res) =>
// console.log(res);
// );
// readBlob(blob, "Text").then((res) =>
// console.log(res);
// );
const App = () =>
useSetRem();
const [size, setSize] = useState(1);
const imgRef = React.useRef<HTMLImageElement>(null);
const [imgUrl, setImgUrl] = useState<string>();
const [imgUrl1, setImgUrl1] = useState<string>();
const [imgUrl2, setImgUrl2] = useState<string>();
const onInputChnge = (e: React.ChangeEvent<HTMLInputElement>) =>
setlastPosition( startX: 0, startY: 0 );
setPosition( startX: 0, startY: 0 );
const file = e.target.files ? e.target.files[0] : null; //input上传的图片是Blob对象
console.log(file instanceof Blob);
const fileReader = new FileReader();
fileReader.readAsDataURL(file!); //转为地址
fileReader.onload = (e) =>
console.log(e.target?.result);
setImgUrl(e.target?.result as string);
imgRef.current?.addEventListener("load", () => drawImage(1));
;
;
// 将图片绘制到canvas
const drawImage = (scale1: any = 1, left = 0, top = 0) =>
console.log(123123);
if (imgRef.current && canvasRef.current)
const image = imgRef.current;
let canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
// 清掉canvas
ctx?.clearRect(0, 0, canvas.width, canvas.height);
//
let imageWidht = image.width;
let imageHieght = image.height;
if (imageWidht > imageHieght)
let scale = canvas.width / imageWidht;
imageWidht = canvas.width;
imageHieght = imageHieght * scale;
else
let scale = canvas.height / imageHieght;
imageHieght = canvas.height;
imageWidht = imageWidht * scale;
imageHieght = imageHieght * Number(scale1);
imageWidht = imageWidht * Number(scale1);
console.log("top", top);
console.log("left", left);
console.log("imageWidht", imageWidht);
requestAnimationFrame(() =>
ctx?.drawImage(
image,
(300 - imageWidht) / 2 + left,
(300 - imageHieght) / 2 + top,
imageWidht,
imageHieght
);
);
;
const canvasRef = React.useRef<HTMLCanvasElement>(null);
const position = React.useRef( startX: 0, startY: 0 );
const setPosition = (e) =>
position.current = e;
;
const lastPosition = React.useRef( startX: 0, startY: 0 );
const setlastPosition = (e) =>
lastPosition.current = e;
;
const Drag = React.useRef(false);
// 按下
const handleMouseDown = (e) =>
console.log("lastPosition", lastPosition);
setPosition(
startX: e.clientX,
startY: e.clientY,
);
Drag.current = true;
;
// 移动
const handleMouseMove = (e) =>
if (Drag.current)
// x方向移动的量, y方向移动的量
drawImage(
size,
e.clientX - position.current.startX + lastPosition.current.startX,
e.clientY - position.current.startY + lastPosition.current.startY
);
;
// 抬起
const handleMouseUp = (e) =>
if (Drag.current)
setlastPosition(
startX:
e.clientX - position.current.startX + lastPosition.current.startX,
startY:
e.clientY - position.current.startY + lastPosition.current.startY,
);
Drag.current = false;
;
// 截图, canvas数据可以通过toDataURL转为url
const confirm = (e) =>
const canvas = canvasRef.current;
const ctx = canvas?.getContext("2d");
// 截取,xy坐标+宽高
const imageData = ctx?.getImageData(100, 100, 100, 100);
const avatarCanvas = document.createElement("canvas");
avatarCanvas.width = 100;
avatarCanvas.height = 100;
const avatrCtx = avatarCanvas.getContext("2d");
avatrCtx?.putImageData(imageData!, 0, 0);
const dataURl = (avatarCanvas as any).toDataURL(); //转为url
setImgUrl1(dataURl);
;
// 转为blob对象可供上传
// atob()用于解码 base64编码的字符串
// btoa()//将字符串编码成base64字符串
const onUpload = (event) =>
const bytes: string = window.atob(imgUrl1!.split(",")[1]);
const arrayBuffer = new ArrayBuffer(bytes.length); //创建一个长度一样大的buffer数组
const uInt8Array = new Uint8Array(arrayBuffer);
for (let i = 0; i < bytes.length; i++)
uInt8Array[i] = bytes.charCodeAt[i];
const blob = new Blob([arrayBuffer], type: "image/png" ); // 转为blob对象
console.log("blob", blob);
const fileReader = new FileReader();
fileReader.readAsDataURL(blob!); //转为地址
fileReader.onload = (e) =>
console.log(e.target?.result);
setImgUrl2(e.target?.result as string);
;
;
return (
<div style= display: "flex" >
<div style= flex: 1 >
<input type="file" accept="image/*" onChange=onInputChnge />
<img ref=imgRef src=imgUrl alt="" />
</div>
<div
style= flex: 1
onMouseDown=handleMouseDown
onMouseMove=handleMouseMove
onMouseUp=handleMouseUp
>
<div style= position: "relative" >
<canvas
ref=canvasRef
width="300px"
height="300px"
style= border: "2px dashed blue"
></canvas>
<div
style=
width: 100,
height: 100,
background: "yellow",
opacity: 0.3,
position: "absolute",
top: 100,
left: 100,
></div>
</div>
<div>
<Button
onClick=() =>
setSize((size * 5) / 4);
console.log(lastPosition);
drawImage(
(size * 5) / 4,
lastPosition.current.startX,
lastPosition.current.startY
);
>
放大
</Button>
<Button
onClick=() =>
setSize((size * 3) / 4);
drawImage(
(size * 3) / 4,
lastPosition.current.startX,
lastPosition.current.startY
);
style= margin: "0 10px"
>
缩小
</Button>
<Button onClick=confirm>截取</Button>
</div>
</div>
<div style= flex: 1 >
<img src=imgUrl1 alt="" />
<Button onClick=onUpload>上传</Button>
<img src=imgUrl2 alt="" />
</div>
</div>
);
;
ReactDOM.render(<App></App>, document.getElementById("root"));
效果:
总结
- 二进制对象有ArrayBuffer,但他一般不可以直接操作,可以通过TypedArray或者DataView操作。
- Blob对象一般是用来上传图片的类型,Blob对象可以通过URL.createObjectURL(blob)转为base64编码。
- FIleReader用来操作Blob对象或者FIle对象,比如上传。可以将File对象转为base64,供img标签使用。
- canvas可以截取数据并且通过canvas.toDataUrl转为base64。
- 通过window.btoa()和二进制对象,可以将base64转为Blob对象供上传。
以上是关于前端二进制-实战的主要内容,如果未能解决你的问题,请参考以下文章