有趣的Js格式转换

更新日期: 2019-07-25 阅读: 2.5k 标签: js知识

Blob

<input type="file" id="avatar" name="avatar" accept="image/png, image/jpeg" />

使用 input 获取文件时,你拿到的就是 file 对象,而 file 继承于 blob,所以直接讲比较陌生的 blob 吧。

BLOB (binary large object),二进制大对象,是一个可以存储二进制文件的“容器”。


Blob 有什么用

使用 Blob 可以让你在浏览器生成一个临时文件,使用 URL.createObjectURL() 获取他的链接,你就能像服务器文件一样使用他。

let temp = new Blob(['hello fantasy'])
URL.createObjectURL(temp)
// 返回 "blob:https://ssshooter.com/1bf84bba-b53a-4155-8348-33a487e8ab7e"

返回的 url 前面是主机,后面是一个唯一识别码。

在创建这个临时文件后,只要不关闭当前页面,这个文件就会一直存在于内存,你需要主动运行 URL.revokeObjectURL(url) 删除引用。


从 Blob 中提取数据

在控制台打出 blob 你根本不知道里面是啥,那么怎么读取 blob 呢?

借助 FileReader,你可以把 Blob 读取为 Buffer。

FileReader 对象允许 Web 应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File 或 Blob 对象指定要读取的文件或数据。
var reader = new FileReader()
reader.addEventListener('loadend', function() {
  // reader.result 包含转化为类型数组的blob
})
reader.readAsArrayBuffer(blob)


ArrayBuffer

经过 FileReader 的读取,你能看到计算机储存数据的本质 —— 二进制数据。

ArrayBuffer 的编辑

ArrayBuffer 类似数组,每一格放入 1Byte(8bit)数据,也就是八位的 0 或 1,所以换成十进制一格最大是 255.

例如:


ArrayBuffer 不能直接操作,而是要通过类型数组对象(下面列出来的)或 DataView 对象来操作,它们会将缓冲区中的数据表示为特定的格式,并通过这些格式来读写缓冲区的内容。

  • Int8Array:8 位有符号整数,长度 1 个字节,溢出处理为 数值%(取模)255。
  • Uint8Array:8 位无符号整数,长度 1 个字节。
  • Uint8ClampedArray:8 位无符号整数,长度 1 个字节,溢出处理为 255(最大值)。
  • Int16Array:16 位有符号整数,长度 2 个字节。
  • Uint16Array:16 位无符号整数,长度 2 个字节。
  • Int32Array:32 位有符号整数,长度 4 个字节。
  • Uint32Array:32 位无符号整数,长度 4 个字节。
  • Float32Array:32 位浮点数,长度 4 个字节。
  • Float64Array:64 位浮点数,长度 8 个字节。

对应视图的转换还很神奇的,ArrayBuffer 是一个格子 8 位,也就是跟 xx8Array 是一样的,自然不用转换,而 16 之后的都是把每几个格子合成一个。

// 创建 buffer
ab = new ArrayBuffer(4)
// 创建视图
a = new Uint8Array(ab)
// 通过视图操作 buffer
a[0] = 2
a[1] = 25
a[2] = 31
a[2] = 233

打印 ab 会输出:


为了方便理解他们如何转换,我把他转为 2 进制:

// Int16Array
;['1100100000010', '11101001']
// Int32Array
;['111010010001100100000010']
// Uint8Array
;['10', '11001', '11101001', '0']

可能还没能看出来?那再在前面补 0:

// Int16Array
;['0001100100000010', '0000000011101001']
// Int32Array
;['00000000111010010001100100000010']
// Uint8Array
;['00000010', '00011001', '11101001', '00000000']

这就很明显能看出:要转换就要在分组之后把同一组数据从右到左拼接。

不过我自觉一般不太会用到这么细致的 bit 操作(

canvas 与 buffer

另外,canvas 可以通过 ctx.createImageData() 得到 ImageData。

ImageData.data 就是一个 Uint8ClampedArray,里面顺序放着图片每一个像素的 rgba 值。你可以对这个 Uint8ClampedArray 进行一系列操作,再用 canvas.toBlob 这个 buffer 变回 Blob,就完成了图片编辑的操作。

通过这个操作,再结合一些卷积核相关知识,就能完成类似这个卷积核图片修改器的功能。


Data Url

Data Url 是一个前缀为 data: 的协议,你可以借助这个协议在文档中嵌入一些小文件(最常见就是内联图片了),数据格式如下:

data:[<mediatype>][;base64],<data>

mediatype 填入MIME 类型,MIME 也用于服务器返回数据时指定数据类型;base64 是一种编码方式;后面接着就是数据本体。

几个例子:

  • 普通文字:data:,Hello%2C%20World!
  • base64 处理的文字:data:text/plain;base64,SGVsbG8sIFdvcmxkIQ%3D%3D
  • html 文档:data:text/html,%3Ch1%3EHello%2C%20World!%3C%2Fh1%3E
  • 执行 script 的 html 文档:data:text/html,<script>alert('hi');</script>


base64

上面提到的 base64 不算是一种加密算法,它只是简单地将每 3 个 8bit 字符转换为 4 个 6Bit 字符(base64 只有 2^6 = 64 种字符,因此得名),这样保证了传输中必定使用 ASCII 中可见字符,不会出奇怪的空白字符或是功能性标志 。

由于是 3 个字符变 4 个,那么很明显了,base64 编码后,编码对象的体积会变成原来的 4/3 倍

特别要注意的是如果 bit 数不能被 3 整除,需要在末尾添加 1 或 2 个 byte(8 或 16bit),并且末尾的 0 不使用 A 而使用 =,这就是为什么 base64 有的编码结果后面会有一或两个等号。

喜闻乐见的举例时间:

前置知识点:utf8 与 unicode 的关系

你可以使用 charCodeAt() 获取一个字符的 unicode 编码(0 到 65535 之间的整数),但是 unicode 只是一个码表,并不是一个具体的编码方式,utf8 才是。所以你拿到的英文字母编码前后一样的,但是汉字(等字符)就不同了。

为了直接得到汉字的 utf8 码,使用 TextEncoder(其实还可以选择使用 encodeURIComponent 处理汉字,但是英文又不能正常转换了)。

下面用 JavaScript 简单写个 base64 转换流程:

var b64 = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
Array.from(new TextEncoder().encode('碧蓝幻想'))
  .map(val => val.toString(2).padStart(8, 0)) // 转二进制,补充到八位
  .join('')
  .replace(/([10]{6})/g, '$1,') // 每六位插个逗号用于拆分
  .split(',') // 拆分为每 6 位一组
  .map(val => parseInt(val.padEnd(6, 0), 2)) // 补充后面的 0(但是没有补够)
  .map(val => b64[val])
  .join('')

结果基本是对的,但是后面的 = 还是用了普通的 A 而且位数没有加够,所以上面转换出来的不是标准 base64,仅供参考

base64 算法参考


blob url 与 Data Url 对比

blob url

  • 不需要做编码,省了运算资源
  • 大小也不会改变
  • 在不使用时需要手动删除引用
  • 关闭页面链接自动废弃

Data Url

  • 需要编码,且体积变大 1.3 倍
  • 容易删除
  • 链接不变,保存了可以以后使用


附录

N 进制数的表示方法

// 10
var a = 10
// 8
var b = 0o1234567
// 或直接在前面加0,如果后面数字都小于8就自动变成8进制
var c = 01234567
// 2
var d = 0b1010101110101
// 16
var e = 0xe87a90

N 进制数转 10 进制

parseInt(0o1234567, 8)
parseInt(0b1010101110101, 2)
parseInt(0xe87a90, 16)

10 进制数转 N 进制

;(123456).toString(2)
;(123456).toString(8)
;(123456).toString(16)


原文来自:https://ssshooter.com/2019-04-18-js-format-transform/


本文内容仅供个人学习、研究或参考使用,不构成任何形式的决策建议、专业指导或法律依据。未经授权,禁止任何单位或个人以商业售卖、虚假宣传、侵权传播等非学习研究目的使用本文内容。如需分享或转载,请保留原文来源信息,不得篡改、删减内容或侵犯相关权益。感谢您的理解与支持!

链接: https://fly63.com/article/detial/4348

相关推荐

js判断日期是否为今天

需求如下:后端返回字符串数据,需要前端判断该日期是否为今天。比如返回日期格式为:2018-08-14,那么需要如何来实现呢,这篇文章整理实现的几种方式供大家参考。

WebSocket的原理及WebSocket API的使用,js中如何运用websocket

WebSocket是HTML5下一种新的协议,为解决客户端与服务端实时通信而产生的技术。其本质是先通过HTTP/HTTPS协议进行握手后创建一个用于交换数据的TCP连接

原生js实现数字三位逗号,分隔。js实现支持逗号分割的货币格式表示法总汇

javascript实现数字三位逗号分隔,如把123456.78转换为123,456.78。js实现支持货币格式表示法:toLocaleString在将数字转换为字符串的同时,会使用三位分节法进行显示。slice 方法用于截取字符串中的一部分并返回该部分字符串。match方式代表正则表达式的匹配....

原生js获取当前周数

通过原生Js根据日期获取对应日期的周数,例如今天是2018-01-01那么获取该日期在这一年的周数就为1,有需要的朋友可以参考下。

JavaScript弹框、对话框、提示框方法,以及原创JS模拟Alert弹出框效果

通过js实现网页弹出各种形式的窗口,常用的:弹出框、对话框、提示框等。弹出对话框并输出一段提示信息 、弹出一个询问框,有确定和取消按钮 ,利用对话框返回的值 (true 或者 false) 、弹出一个输入框,输入一段文字,可以提交、window.open 弹出新窗口的命令

js中&与&&,|与||的区别

&、|、~都是位操作符,而&&、|、~|都是逻辑操作!。&&是逻辑与运算符假前真后,||是逻辑或运算符真前假后,&是按位与操作两个数值的个位分别相与,同时为1才得1,只要一个为0就为0。

js可以设置网页默认为横屏状态吗?js设置网页横屏和竖屏切换

打开页面时通过 window.orientation 可以判断网页是横屏还是竖屏,如果是竖屏,给整个页面添加样式 transform: rotate(90deg); 这样,你的页面就显示横屏的效果了。 总的来说,结合window.orientationchange和window.orientation可以灵活的对网页进行变换。

原生js判断当前页面是否为激活状态【判断用户是否在浏览当前页面】

但浏览器打开多个网页时候,如何判断我这个页面是否正在被用户浏览呢?我们可以通过document.hidden属性判断当前页面是否是激活状态。

javascript对dom的操作总汇,js创建,更新,添加,删除DOM的方法

HTML文档在浏览器解析后,会成为一种树形结构,我们需要改变它的结构,就需要通过js来对dom节点进行操作。dom节点(Node)通常对应的是一个标题,文本,或者html属性。

js秒数转换成时分秒_js如何将秒拼接为时分秒显示?

接口返回的是int类型的秒数,在前端显示要求拼接为时分秒显示,这篇文章主要讲解实现js秒数转换成时分秒的方法。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!