纯前端实现 PNG 图片压缩 | UPNG.js
在线 Demo 体验地址 →: https://demos.sugarat.top/pages/png-compress/
前言
最近在迭代自己的 图床 应用,由于使用时间的累计,存储空间占用越来越大了,在做 Web 应用的时候会随手拿 tinypng 压缩一下图片。
想着给咱图床也加个压缩的功能,这样上传/访问也能省点 。
图片类型众多,常用的主要就是PNG/JPG/GIF。
个人使用频率最高的场景是截图上传,格式为PNG,就先拿 PNG 试手。调研了一圈开源里最流行的就是使用 UPNG.js 进行 PNG 的压缩。
如何判断图片是 PNG
第一步当然是判断图片类型,不然 UPNG.js 就不能正常工作咯,通过文件后缀 .png 判断肯定是不靠谱的。
搜索了解了一下,可以使用 魔数 判断:一个PNG文件的前8个字节是固定的。
PNG 的前 8 个字节是(16进制表示):89 50 4E 47 0D 0A 1A 0A。
我们可以拿工具看一下,我这里用 VS Code 插件 Hex Editor 查看一个 PNG 图片的 16 进制表示信息。
可以看到前八个字节和上面表示的一样。
于是可以根据这个特性判断,于是就有如下的判断代码。
async function isPNG(file: File) {
// 提取前8个字节
const arraybuffer = await file.slice(0, 8).arrayBuffer()
// PNG 的前8字节16进制表示
const signature = [0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A]
// const signature = [137, 80, 78, 71, 13, 10, 26, 10]
// 转为 8位无符号整数数组 方便对比
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array
const source = new Uint8Array(arraybuffer)
// 逐个字节对比
for (let i = 0; i < signature.length; i++) {
if (source[i] !== signature[i]) {
return false
}
}
return true
}
UPNG.js
简介
一个轻量且极速的
PNG/APNG编码和解码库,Photopea 图像编辑器的主要PNG引擎。
npm 加载
官方提供了 npm 包,简单引入即可使用。
安装依赖
npm install upng-js
核心方法就 3 个,依次调用即可
- UPNG.decode(buffer)
- UPNG.toRGBA8(img)
- UPNG.encode(imgs, w, h, cnum, [dels])
- cnum:0 表示无损压缩,256表示有损,可以调整这个值来控制压缩质量。
注意:压缩并不意味着一定小,对于一些已经很简单且小的图片,压缩后可能反而更大。
下面是这个方法的最简实现。
import UPNG from 'upng-js'
async function compressPNG(file: File) {
const arrayBuffer = await file.arrayBuffer()
const decoded = UPNG.decode(arrayBuffer)
const rgba8 = UPNG.toRGBA8(decoded)
// 关键的压缩方法
// 这里 保持宽高不变,保持80%的质量(接近于 tinypng 的压缩效果)
const compressed = UPNG.encode(
rgba8,
decoded.width,
decoded.height,
256 * 0.8
)
return new File([compressed], file.name, { type: 'image/png' })
}
其中压缩后的宽高,压缩质量都是可以调整的。
可配置封装
下面方法(TS 实现),提供了一些常用的配置选项。
import UPNG from 'upng-js'
interface CompressOptions {
/**
* 压缩质量([0,1])
* @default 0.8
*/
quality?: number
/**
* 压缩后更大是否使用原图
* @default true
*/
noCompressIfLarger?: boolean
/**
* 压缩后的新宽度
* @default 原尺寸
*/
width?: number
/**
* 压缩后新高度
* @default 原尺寸
*/
height?: number
}
async function compressPNGImage(file: File, ops: CompressOptions = {}) {
const { width, height, quality = 0.8, noCompressIfLarger = true } = ops
const arrayBuffer = await file.arrayBuffer()
const decoded = UPNG.decode(arrayBuffer)
const rgba8 = UPNG.toRGBA8(decoded)
const compressed = UPNG.encode(
rgba8,
width || decoded.width,
height || decoded.height,
256 * quality
)
const newFile = new File([compressed], file.name, { type: 'image/png' })
if (!noCompressIfLarger) {
return newFile
}
return file.size > newFile.size ? newFile : file
}
CDN 加载
不通过 npm 安装,也可以使用 <script> 标签的方式进行全局引入。
可以使用Static file提供的 CDN 资源。
只需在 HTML 模板顶部 head 中加入如下资源即可使用。
<head>
<script src="https://cdn.staticfile.net/pako/1.0.5/pako.min.js"></script>
<script src="https://cdn.staticfile.net/upng-js/2.1.0/UPNG.min.js"></script>
</head>
PNG 格式化使用 Inflate 算法。这部分调用 Pako.js 实现,所以需要额外前置引入。
引入后,将在 window 上绑定 UPNG 变量,使用和上述 npm 给到的例子完全一致。
代码里调用方式如下
window.UPNG.encode
// 省略 window
UPNG.encode
完整 demo
笔者将本节内容整理成了一个 Demo,可以直接在线体验。
在线 Demo 体验地址 →: https://demos.sugarat.top/pages/png-compress/
大概界面如下:
纯血 HTML/CSS/JS,复制粘贴就能运行。
完整源码见:GitHub:ATQQ/demos - png-compress
最后
后续将继续学习&探索一下其它格式的纯前端压缩实现(JPG,GIF,MP4转GIF)。
纯前端实现 PNG 图片压缩 | UPNG.js的更多相关文章
- 图片上传前 压缩,base64图片压缩 Exif.js处理ios拍照倒置等问题
曾写过在前端把图片按比例压缩不失真上传服务器的前端和后台,可惜没有及时做总结保留代码,只记得js利用了base64位压缩和Exif.js进行图片处理,还有其中让我头疼的ios拍照上传后会倒置等诸多问题 ...
- 前端构建工具 Gulp 压缩合并JS/CSS 并添加版本号、ES6转ES5
Gulp 基于 Node.js 的前端构建工具,可以实现前端代码的编译(sass.less).压缩合并(JS.CSS).测试:图片的压缩:已经添加 JS 和 CSS 版本号,防止浏览器缓存. 1. 安 ...
- 图片压缩(js压缩,底部有vue压缩图片依赖使用的教程链接)
directTurnIntoBase64(fileObj, callback) { var r = new FileReader(); // 转成base64 r.onload = function( ...
- HTML5时代的纯前端上传图片预览及严格图片格式验证函数(转载)
原文地址:http://www.2cto.com/kf/201401/274752.html 一.要解决什么样的问题? 在写这个函数之前,有们童鞋在群里问如何纯前端严格验证图片格式.这在html5时代 ...
- 图片纯前端JS压缩的实现
一.图片上传前端压缩的现实意义 对于大尺寸图片的上传,在前端进行压缩除了省流量外,最大的意义是极大的提高了用户体验. 这种体验包括两方面: 由于上传图片尺寸比较小,因此上传速度会比较快,交互会更加流畅 ...
- JS魔法堂之实战:纯前端的图片预览
一.前言 图片上传是一个普通不过的功能,而图片预览就是就是上传功能中必不可少的子功能了.在这之前,我曾经通过订阅input[type=file]元素的onchange事件,一旦更改路径则将图片上传至服 ...
- 纯原生js移动端图片压缩上传插件
前段时间,同事又来咨询一个问题了,说手机端动不动拍照就好几M高清大图,上传服务器太慢,问问我有没有可以压缩图片并上传的js插件,当然手头上没有,别慌,我去网上搜一搜. 结果呢,呵呵...诶~又全是基于 ...
- 使用HTML5的两个api,前端js完成图片压缩
主要用了两个html5的 API,一个file,一个canvas,压缩主要使用cnavas做的,file是读取文件,之后把压缩好的照片放入内存,最后内存转入表单下img.src,随着表单提交. 照片是 ...
- 前端构建工具之gulp(一)「图片压缩」
前端构建工具之gulp(一)「图片压缩」 已经很久没有写过博客了,现下终于事情少了,开始写博吧 今天网站要做一些优化:图片压缩,资源合并等 以前一直使用百度的FIS工具,但是FIS还没有提供图片压缩的 ...
- 移动前端—H5实现图片先压缩再上传
在做移动端图片上传的时候,用户传的都是手机本地图片,而本地图片一般都相对比较大,拿iphone6来说,平时拍很多图片都是一两M的,如果直接这样上传,那图片就太大了,如果用户用的是移动流量,完全把图片上 ...
随机推荐
- Java并发(十四)----悲观互斥与乐观重试
1. 悲观互斥 互斥实际是悲观锁的思想 例如,有下面取款的需求 interface Account { // 获取余额 Integer getBalance(); // 取款 ...
- Linux sed输出文件内容的某几行
命令: sed -n "开始行,结束行p" 文件名 sed -n '70,75p' 文件名 # 输出第70行到第75行的内容 sed -n '6p;26 ...
- Hive3.1.2安装部署
一.安装Hive3.1.2 备注:在安装Hive3.1.2之前,请首先安装Hadoop3.1.3. 1. 下载并解压Hive安装包 tar -zxvf ./apache-hive-3.1.2-bin. ...
- CF-925(已更新:D-F)
CF 925 补题ing 待更新 后面打算更新D题和power oj上一道区间合并的题(现在才知道是一道洛谷上的原题--) D 分析 涉及到关于取模的知识,我们的答案要满足三个条件: ai-aj≡ ...
- Pandas 人口密度案例分析
from turtle import left import pandas as pd """ 需求: 1.导入文件,查看原始数据 2.将人口数据和各州简称数据进行合并 ...
- Power BI 6 DAY
Power BI 数据建模与数据汇总分析 层级关系 跨表取字段时类型二可用 父子级关系条件 一个父级下对应多个子级值 一个子级值只属于一个父级 跨表取字段的条件:维度连接用关键字段间是父子级关系时,可 ...
- NC16810 [NOIP1999]拦截导弹
题目链接 题目 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达 ...
- low-code 低代码平台 java 代码自动一键生成工具
low-code low-code 是一款为 java 打造的低代码平台. 开源地址:https://github.com/houbb/low-code 特性 支持基本的增删改查 支持枚举值处理 支持 ...
- python中两个不同shape的数组间运算规则
1 前言 声明:本博客讨论的数组间运算是指四则运算,如:a+b.a-b.a*b.a/b,不包括 a.dot(b) 等运算,由于 numpy 和 tensorflow 中都遵循相同的规则,本博客以 nu ...
- HTML+CSS设计一个朴实无华的登录页
说明 之前一直偏重于后端技术研究,最近设计网站感觉前端太菜,遂集中看了下CSS的内容.后续我会发表一些前端实战的一些例子,给自己记录的同时希望也能分享给大家. 实现效果 主要知识点 DIV屏幕垂直居中 ...