webP压缩
# webp压缩
# 优越性
本节内容主要来自: Web图片优化(一):压缩方案简介 (opens new window)
WebP 对大多数图片有着更好的压缩率和图片质量。这里有一个把图片压到相同的质量下,以 JPG 为基准,WebP 和 AVIF 图片体积的对比:
可以看到 WebP 的体积通常比 JPG 小30%,所以给图片转码个 WebP 作为渐进增强是十分有价值的。
下面那 2.7% 负优化情况在本文后面会有讲解。
# 对比:AVIF # (opens new window)
AVIF 是 AV1 视频编码对应的图片格式,AV1(对应VP10) 是 VP8 的下两代,AVIF 也就成为了 WebP 的继任者,它拥有比 WebP 更高的压缩率和更好的质量。
在上面的对比图里 AVIF 压缩率比 WebP 高了 20%,而且没有负优化的情况。
# 兼容性(2023.01)
https://caniuse.com/?search=a%27vi%27f
因为比较新,兼容性上自然没有 WebP 那么乐观,Chrome 和 Firefox 都提供了支持;套壳浏览器 Edge 使用的是 Chrome 的内核所以也会支持的;苹果同样是 Alliance for Open Media (opens new window) 的成员,Safari 的支持只是时间问题。可以肯定的是 AVIF 将成为下一个被广泛使用的图片编码。
不过目前 AVIF 的生态还未成型,Netflix 等大厂支持 AV1 也都是今年才开始的。在写本文时 AVIF 正迎来一个爆发期,各种评测层出不穷,可见其受欢迎的程度。
不过本站目前没有使用 AVIF 图,不是我不想用,而是在测试时出现了一些问题:
- 编码太慢,比 WebP 慢了 20 倍不止,还是先等等优化再说。尤其是一千万以上像素的大图,编解码几秒到十几秒,完全无法忍受
- 压缩率不理想,在测试中全部155张图里只有极个别压缩率和质量超过 WebP,大部分体积反而比 WebP 大了好几倍。当然我还没有研究 AVIF 的转换参数,不知道 Netfilx 他们是用得什么参,也没有找到调优方面的文章。
# 兼容性-2022
# 浏览器/webview
https://caniuse.com/?search=Webp
如下图: 解码几乎全部支持: 97.3%,编码支持性一般: 77.79%
Js api对webp的支持一般, 比如下方的 webp编码的api(使用canvas api将图片转换/压缩成webp)
# Android
Android 4.0 以下不支持 WebP 图片格式 ; ( 不能使用 )
Android 4.0 以上支持 不带透明度 并且是 无损压缩 的 WebP 图片 ; ( 有限度的使用 , 不带透明度的图片 , 压缩量有限)
Android 4.2.1 以上的系统 , 支持 有损压缩 , 带透明度 的 WebP 图片 ; ( 完全支持 WebP 格式图片 )
也就是说 , 只有 4.2.1 4.2.14.2.1 以上的系统 , 才完全支持 WebP 图片格式 ;
现在基本上开发时设置的最小兼容版本都是 4.3 , 可以完全兼容 WebP 格式图片 ;
质量相同情况下,WebP 格式图像的体积要比 JPEG 格式图像小 40%,但 WebP 格式图像的编码时间比 JPEG 格式图像长 8 倍
# webp的exif编辑bug
https://developer.android.com/jetpack/androidx/releases/exifinterface
implementation "androidx.exifinterface:exifinterface:1.3.5"
# 版本 1.3.5
2022 年 10 月 24 日
发布了 androidx.exifinterface:exifinterface:1.3.5
。版本 1.3.5 中包含这些提交内容 (opens new window)。
bug 修复
- 修复了
saveAttributes()
产生无效 WebP 文件的两种情况。
经验证,确实解决了这个bug
# Android上如何支持下方的压缩参数?
不支持设置-sharp_yuv,但设置quality=100等效于-lossless
bool compress (Bitmap.CompressFormat format, int quality, OutputStream outputStream)
对于webp来说,quality要么是75,要么是100, 不要设其他的值.
截带文本的屏,推荐用无损(100), 即使同样是无损,webp的无损也要比jpg的无损(质量100)文件体积小很多. 如下图:
如果使用有损webp,那么文字亮度明显变暗,被周围像素混淆
更加明显的是这张代码截图
有损webp压缩
无损webp压缩
其他拍照,视频截图,用75即可
综合策略:
如果一张图是png,或者质量为100的jpg,以及通过exif识别非相机拍照的照片:
那么压缩时同时压缩一份无损webp和有损webp(质量75), 谁小用谁. 注意无损webp压缩会比较耗时,要几秒.
如果是质量小于100的jpg,那么使用webp有损压缩,质量75.
各种截图软件的输出应设置为png输出,picgo压缩使用上述策略.
# 压缩参数选择和优化
Web图片优化(一):压缩方案简介 (opens new window)
Web图片优化(二):WebP 参数分析 (opens new window)
美图图像选型评测及优化历程 (opens new window)
-q 75
-m 5
-sharp_yuv
2
3
当一张图上传后,如果是PNG(JPG 很少出现此问题)则同时使用有损和无损两种模式压缩,然后选择体积小的一个
# 修改图片尺寸时,目标图片分辨率的选择:
最好是16*16的倍数
Google最新的图片格式WEBP全面解析 (opens new window)
# 一些不足
# 对png图片的损耗
WebP 压缩后的图片甚至能比原图还大,在官网上也有对此的描述:can_a_webp_image_grow_larger_than_its_source_image (opens new window)
左边的是有损模式,可以看到红色的字符串、紫色的关键字、以及绿色的注释部分都有色彩失真,而且文件体积是无损模式的7倍。有损压缩我还加了-sharp_yuv
参数的,要是没这个参数那简直没法看。
你可以自己尝试一下,把 这张图 (opens new window) 上传到 squoosh (opens new window) 并选择 WebP Compress,看看它是怎么把你的图压成一坨屎的。
因为有这些问题,所以不能无脑把所有图片全用 cwebp 默认参数直接压。
那么怎么解决呢,目前我的方案是根据文件体积增加这一特征来检测。当一张图上传后,如果是PNG(JPG 很少出现此问题)则同时使用有损和无损两种模式压缩,然后选择体积小的一个。
这样无论是插画还是文字都能很好地处理,但如果遇到混合的那就无效了,不过这种情况应该很少。
# Animated WebP的兼容性和动态图方案
# 动效图方案 (opens new window):
建议的解决方案排序是 PAG>VAP>Lottie>WebP/APNG...,例如在 iOS 平台,所有的 PAG 文件播放都有比较不错的体验,因此我们更建议使用 PAG 交付,而在 Android 端 WebP 的稳定性更好,因此在 Android 更建议使用 WebP,当然在 Web 端依然可以使用 Lottie、WebP 作为平替。
# 2022 年 Web 端主流动画实现方案 (opens new window):
动态图片开发成本低,但是动态图片无法交互;
帧动画控制性一般,开发成本一般。但图片体积和动画帧数成正比,无法做到帧间压缩;
属性动画控制性高,开发成本随动画复杂度成正比;
使用动画 SDK 可以做到动画效果的极致还原,前端开发动画成本低,可操控性非常高,素材体积低。
# 一些测试案例
png压缩为webp的测试-表情图 (opens new window)
gif压缩为webp的测试 (opens new window)
WebP 转换的示例链接-又拍云 (opens new window)
# 应用
# Android
图片缓存库的本地缓存文件瘦身 :
glide onResourceReady回调里把图片压缩成webp并覆盖原文件--> 直接开一个fileObserver线程,监听glide和fresco缓存文件夹的文件变化,有新创建的文件,就压缩成webp
# 各云存储/cdn图片处理的支持
# 腾讯云
# 阿里云
# 七牛
- 七牛提供了高级图像处理的功能
- 通过URL后拼接参数,能把gif图处理成webp
- 1.安卓下七牛CDN借用高级图像处理功能form成webp(IOS维持GIF图原样)
- 2.JS判断是否支持webp如果支持,把gif图通过七牛处理成webp动态图,不支持维持原样。
- HTML5标签 picture,是一套精简的兼容方案,浏览器兼容可通过此标签来展示对应的图片
<picture>
<source srcset="https://dn-odum9helk.qbox.me/test.gif?imageMogr2/thumbnail/100x|imageMogr2/format/webp" type="image/webp" />
<img src="https://dn-odum9helk.qbox.me/test.gif?imageMogr2/thumbnail/100x" alt="MDN" />
</picture>
2
3
4
# 各语言/系统对图片压缩格式的支持
# Android-bitmap编解码
4.4以上, 全系列支持
https://github.com/hss01248/jpegQuality JAVA 计算jpg质量因子, Android和JAVA后台均可用
https://github.com/skyNet2017/Luban : Android
# java imageIO
https://github.com/coobird/thumbnailator java图片压缩工具,仅对imageIO的API封装
要支持webp读写,需要给ImageIO加插件:
比如
https://github.com/haraldk/TwelveMonkeys 只支持读/解码,不支持webp编码
https://github.com/nintha/webp-imageio-core 还需要自己编译,麻烦
https://github.com/sejda-pdf/webp-imageio 原生库打包好了到mavencentral---推荐
https://github.com/umjammer/vavi-image-webp 比较新
# js-web
纯浏览器端图片压缩,需要基于canvas api, 对webp的支持只有78%,
需要兼容处理: 如果不支持webp输出,则压缩为png或jpg.
以下的库用于生产均需要做兼容处理
https://github.com/alextanhongpin/compress.js 主要是输出为jpg
- When working with
image/gif
, the compressed image will no longer animate. - When working with
image/png
with transparent background, the compressed image will lose transparency and result in black background.
https://github.com/brunobar79/J-I-C To compress the image, first it converts an image object to canvas and then compress it with the canvas method toDataURL(mimetype, quality), toDataURL对webp支持一般(编码)
https://github.com/idiotWu/canvas-compress 同上,对webp输出的支持一般.
# nodejs
https://github.com/imagemin/imagemin
https://github.com/imagemin/imagemin-webp
# flutter
https://pub.dev/packages/flutter_image_compress flutter图片压缩-Android/ios
https://pub.dev/packages/image_compression 另一个纯dart图片压缩库
https://pub.dev/packages/flutter_luban 纯dart,支持除web外所有平台
image_compression_flutter (opens new window) Combining use of packages :
- image_compression (opens new window) :
MacOS
,Windows
,Linux
andWeb
- flutter_image_compress (opens new window) :
Android
andiOS
# squoosh-图片压缩对比工具
by google
# web网址
https://squoosh.app/
# cli版本
Node js
https://yjyj.net/learn/6261.html
# npm
https://www.npmjs.com/package/unplugin-imagemin
# picgo插件
https://www.npmjs.com/package/picgo-plugin-squoosh
# java webp相关解决方案
# java imageIO
https://github.com/coobird/thumbnailator java图片压缩工具,仅对imageIO的API封装
要支持webp读写,需要给ImageIO加插件:
比如
https://github.com/haraldk/TwelveMonkeys 只支持读/解码,不支持webp编码
https://github.com/nintha/webp-imageio-core 还需要自己编译,麻烦
https://github.com/sejda-pdf/webp-imageio 原生库打包好了到mavencentral---推荐
https://github.com/umjammer/vavi-image-webp 比较新
# sejda-pdf/webp-imageio# (opens new window)
在Java中,可以使用这个库:sejda-pdf/webp-imageio: Java ImageIO WebP support (opens new window) 其封装了多个系统的libwebp库版本,可以在Linux、Mac、Windows中使用,同时还发布在了Maven中。 但有一个问题,就是这个库,不能将GIF图片转为动态的webp文件。只会将GIF图片第一帧转为webp文件,也就是一张静态的图片。
// Obtain a WebP ImageReader instance
ImageReader reader = ImageIO.getImageReadersByMIMEType("image/webp").next();
// Configure decoding parameters
WebPReadParam readParam = new WebPReadParam();
readParam.setBypassFiltering(true);
// Configure the input on the ImageReader
reader.setInput(new FileImageInputStream(new File("input.webp")));
// Decode the image
BufferedImage image = reader.read(0, readParam);
2
3
4
5
6
7
8
9
10
11
12
GIF转webP动画的Java库:
# 调用 gif2webp# (opens new window)
gif2webp (opens new window) 是Google提供的sdk中的一个可执行工具,使用起来也很简单。
Copygif2webp.exe .\gif.gif -o gif.webp
# 封装比较完善的库:
https://sksamuel.github.io/scrimage/webp/
<!-- https://mvnrepository.com/artifact/com.sksamuel.scrimage/scrimage-core -->
<dependency>
<groupId>com.sksamuel.scrimage</groupId>
<artifactId>scrimage-core</artifactId>
<version>4.0.32</version>
</dependency>
<!-- https://mvnrepository.com/artifact/com.sksamuel.scrimage/scrimage-webp -->
<dependency>
<groupId>com.sksamuel.scrimage</groupId>
<artifactId>scrimage-webp</artifactId>
<version>4.0.32</version>
2
3
4
5
6
7
8
9
10
11
代码
public static File toWebP(String path) throws Exception{
long start = System.currentTimeMillis();
File file = new File(path);
ImmutableImage image = ImmutableImage.loader().fromFile(file);
String name = file.getName().substring(0,file.getName().lastIndexOf(".")+1)+"webp";
File newPath = new File(file.getParent(),name);
Path output = image.output(WebpWriter.DEFAULT, newPath.getAbsolutePath());
String desc = file.getAbsolutePath()+" -> "+name+"\n"+(file.length()/1024)+"kB->"+(newPath.length()/1024)+"kB,缩小:"+
(file.length()-newPath.length())*100/file.length()+"%, 耗时:"+(System.currentTimeMillis()- start)+"ms";
System.out.println(desc);
int quality = new Magick().getJPEGImageQuality(file);
System.out.println("原图jpg质量: "+ quality);
return newPath;
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# 测试
尼康相机拍照的压缩-2400万像素
* 尼康相机拍照的压缩:
* E:\photos\编年史\2022\20220305小区内\DSCN1743.JPG -> DSCN1743.webp
* 2695kB->990kB,缩小:63%, 耗时:10954ms
* 原图jpg质量: 86
2
3
4
原图和webp按100%显示,对比细节,无明显差异. 右侧图为压缩后的webp
压缩小米11ultra手机拍照的图
E:\photos\imgsync\Xiaomi-M2102K1C-gtgdgrd\0\DCIM\Camera\IMG_20220502_104724.jpg -> IMG_20220502_104724.webp 2170kB->1334kB,缩小:38%, 耗时:7808ms 原图jpg质量: 85
压缩时间远比Android要长,在Android上压缩同等大小的,只要1-3s
# gif转webp
兼容性很差.
Android本身都不支持webp动画,需要第三方库,比如
compile 'com.facebook.fresco:animated-webp:0.12.0'
compile 'com.facebook.fresco:animated-gif:0.12.0'
2
https://github.com/humorousz/AnimationSequenceDrawable
压缩率不高,见下方:
D:\Users\Administrator\testgif\14024630.gif -> 14024630.webp 756kB->609kB,缩小:19%, 耗时:6028ms D:\Users\Administrator\testgif\cd112e456ab037dd148f44aab6ab9e9b.gif -> cd112e456ab037dd148f44aab6ab9e9b.webp 2432kB->2037kB,缩小:16%, 耗时:4351ms D:\Users\Administrator\testgif\dave.gif -> dave.webp 8kB->6kB,缩小:22%, 耗时:58ms D:\Users\Administrator\testgif\e5145a1f6ea348e524f3c977d3f32249.gif -> e5145a1f6ea348e524f3c977d3f32249.webp 1496kB->1211kB,缩小:19%, 耗时:1979ms D:\Users\Administrator\testgif\jim.gif -> jim.webp 14kB->12kB,缩小:14%, 耗时:65ms D:\Users\Administrator\testgif\NR6KJFGMS5874.gif -> NR6KJFGMS5874.webp 17kB->12kB,缩小:28%, 耗时:80ms D:\Users\Administrator\testgif\NTPSpqv0yrbpqfep.gif -> NTPSpqv0yrbpqfep.webp 962kB->755kB,缩小:21%, 耗时:1097ms D:\Users\Administrator\testgif\tumblr_mh3ts2XBSM1rbrhnko1_500.gif -> tumblr_mh3ts2XBSM1rbrhnko1_500.webp 657kB->466kB,缩小:29%, 耗时:875ms D:\Users\Administrator\testgif\v2-ec4d371b26dad923867b2752eca734ad_b.gif -> v2-ec4d371b26dad923867b2752eca734ad_b.webp 932kB->819kB,缩小:12%, 耗时:1723ms
综上,gif不应转为webp,而是保持gif格式.
# webp文件元信息的获取
# 判断是否为动图,是否有透明通道
Java后端以MultipartFile形式接受webp图片,并判断是否为动图 (opens new window)
读取动图webp二进制流,前两行会包含一个 ANIM
字符串。否则则为静态,静态图片的二进制流前两行也会包含一个字符串 ALPH
public Integer uploadPicture(MultipartFile multipartFileImageFile) throws IOException {
// 定义动图标记,1表示动图
Integer animated = 0;
BufferedReader br;
String line;
InputStream is = multipartFileImageFile.getInputStream();
br = new BufferedReader(new InputStreamReader(is));
// 二进制流有很多行,我们只需要读取前两行就可以判断
int count = 0;
while ((line = br.readLine()) != null) {
// 为保险起见,我们读取5行,如果其中包含"ANIM"则为动图
if (line.contains("ANIM")) {
animated = 1;
}
if (count++ >= 5) {
break;
}
}
return animated;
}
————————————————
版权声明:本文为CSDN博主「lzx专业攻城狮」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44123540/article/details/118796972
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# webp的exif支持
android里已经完美支持webp的exif的读写,那么java里的呢?
# **metadata-extractor (opens new window)**是否支持?
支持webp的metadata的读,但不支持写. 这个库对所有媒体格式都是只支持读,不支持写.
# groupdocs
https://blog.groupdocs.com/metadata/handle-exif-data-of-jpg-png-webp-images-in-java/
# exiftool是否支持?
ExifTool Forum-WebP-Support / webpmux (opens new window)
October 01, 2022, 02:53:56 PM (opens new window)
ExifTool 12.46 is now available with the ability to add/delete/edit EXIF, XMP and ICC_Profile in WebP images.
# java 里对jpg exif的读写的库
https://commons.apache.org/proper/commons-imaging/sampleusage.html
https://github.com/SichengYang/Java-JPEG-Exif-GeoTag-Editor