一分钟让您的APP支持AVIF图片

导语

AVIF 是一种基于 AV1 视频编码的新一代图像格式,压缩率高,画面细节好。移动端 APP 经常面临网络环境不稳定、需要帮用户节省流量等场景,那就使用 AVIF 图片吧。不过 AVIF 目前只在 iOS16、Android12 上得到原生支持,很多机型覆盖不到,怎么办?本文来教你一分钟集成 AVIF 解码器,兼容所有机型。

AVIF 简介

AVIF 是一种基于 AV1 视频编码的新图像格式,相对于 JPEG ,WEBP 这类图片格式来说,它的压缩率更高,并且画面细节更好。而最关键的是,AV1 由谷歌发起的 AOM (开放媒体联盟)推动,在 VP9 的基础上继续演进,无专利授权费用(而且腾讯也是 AOM 的创始成员哦),关于更多的 AVIF 介绍,可以自行搜索,这里不再赘述。

APP 显示 AVIF 图片

由于 AVIF 目前只在 iOS16、Android12 上得到原生支持,要想覆盖所有主流机型,单靠原生支持肯定是不够的。因此需要客户端开发时集成 AVIF 解码器自行解码,
业内开源编解码库:开源编解码库
腾讯自研编解码库:本文的数据万象 AVIF SDK 基于该编解码库。
直接使用上述解码库,需要自行编译 Android 和 iOS 解码器产物,以及写一些 JNI 代码,如果您的 APP 使用 Glide、SDWebImage 等图片库,还得再按照图片库的要求进行封装集成。这些有不少的工作量,本文叫”一分钟让APP支持AVIF图片“显然是有更快的方法,那就是接入数据万象 AVIF SDK,上述这些事情我们已经帮您做好啦。

数据万象 AVIF 图片 SDK

Android 一分钟集成

使用 Glide 图片库

  1. 安装 Glide 和 AVIF SDK
implementation 'com.qcloud.cos:avif:1.1.0'   
implementation 'com.github.bumptech.glide:glide:version'
annotationProcessor 'com.github.bumptech.glide:compiler:version' 
  1. 注册解码器 GlideModule
// 注册自定义 GlideModule
// 开发者应该创建此类注册相关解码器
// 类库开发者可以继承 LibraryGlideModule 创建类似的注册类
@GlideModule
public class MyAppGlideModule extends AppGlideModule {
    @Override
    public void registerComponents(@NonNull Context context, @NonNull Glide glide, Registry registry) {
        /*------------------解码器 开始-------------------------*/
        //注册 AVIF 静态图片解码器
        registry.prepend(Registry.BUCKET_BITMAP, InputStream.class, Bitmap.class, new StreamAvifDecoder(glide.getBitmapPool(), glide.getArrayPool()));
        registry.prepend(Registry.BUCKET_BITMAP, ByteBuffer.class, Bitmap.class, new ByteBufferAvifDecoder(glide.getBitmapPool()));
        //注册 AVIF 动图解码器
        registry.prepend(InputStream.class, AvifSequenceDrawable.class, new StreamAvifSequenceDecoder(glide.getBitmapPool(), glide.getArrayPool()));
        registry.prepend(ByteBuffer.class, AvifSequenceDrawable.class, new ByteBufferAvifSequenceDecoder(glide.getBitmapPool()));
        /*------------------解码器 结束-------------------------*/
    }
}
  1. 使用 Glide 加载图片
    像普通 jpg png 图片那样加载图片即可,请参见 Glide 官方文档
Glide.with(context).load(url).into(imageView);

使用 Fresco 图片库

  1. 安装 Fresco 和 AVIF SDK
implementation 'com.qcloud.cos:avif:1.1.0'   
implementation 'com.facebook.fresco:fresco:version'
// 如果需要支持 avif 动图解码器 则需要加上 fresco:animated-base 依赖
implementation 'com.facebook.fresco:animated-base:version'
  1. 配置解码器
// 解码器配置
ImageDecoderConfig imageDecoderConfig = new ImageDecoderConfig.Builder()
         // 配置 AVIF 静态解码器
        .addDecodingCapability(
                AvifFormatChecker.AVIF,
                new AvifFormatChecker(),
                new FrescoAvifDecoder())
        // 配置 AVIF 动图解码器
        .addDecodingCapability(
                AvisFormatChecker.AVIS,
                new AvisFormatChecker(),
                new FrescoAvisDecoder())
        .build();
// 配置 Image Pipeline
ImagePipelineConfig config = ImagePipelineConfig.newBuilder(context)
        .setImageDecoderConfig(imageDecoderConfig)
        .build();
// 初始化 Fresco
Fresco.initialize(context, config);
  1. 使用 Fresco 加载图片
    像普通 jpg png 图片那样加载图片即可,请参见 Fresco 官方文档
<com.facebook.drawee.view.SimpleDraweeView
    android:id="@+id/my_image_view"
    android:layout_width="130dp"
    android:layout_height="130dp"
    fresco:placeholderImage="@drawable/my_drawable"
  />


Uri uri = Uri.parse("https://xxx.com/test.avif");
SimpleDraweeView draweeView = (SimpleDraweeView) findViewById(R.id.my_image_view);
draweeView.setImageURI(uri);

iOS 一分钟集成

  1. 安装 SDWebImage 和 AVIF SDK
    在您工程 Podfile 文件中添加模块:
pod 'CloudInfinite/SDWebImage-CloudInfinite'
pod 'CloudInfinite/AVIF'

在终端执行安装命令:

pod install
  1. 使用 SDWebImage 直接加载 AVIF 图片
    SDWebImage-CloudInfinite 模块在 APP 启动时已自动将 AVIF 解码器加入到 SDWebImage 解码器队列中,在加载解码器时自动找到 AVIF 解码器来解码图片。支持动图,无需额外操作。使用时与 SDWebImage 使用没有任何区别。

Objective-C:

[imageView sd_setImageWithURL:[NSURL URLWithString:@"AVIF 图片链接"]];

Swift:

UIImageView() .sd_setImage(with: NSURL.init(string: "AVIF 图片链接"))

数据万象 AVIF SDK 其他功能

基础解码器

用于直接将 AVIF 数据解码为 bitmap、UIImage,以及判断图片数据是否是 AVIF 格式

Android:

import com.tencent.qcloud.image.avif.Avif;

// 图片的字节数组
byte[] buffer = new byte[XXX];
// 是否是 AVIF 格式
boolean isAvif = Avif.isAvif(buffer);
// 是否是 AVIF 动图 
boolean isAvis = Avif.isAvis(buffer);

// 原图解码
Bitmap bitmap = Avif.decode(buffer);

// 宽度等比解码
// 目标宽度
int dstWidth = 500; 
Bitmap bitmap = Avif.decode(buffer, dstWidth);

// 区域缩放解码
// 区域左上角x坐标
int x = 0;
// 区域左上角y坐标
int y = 0;
// 区域宽度
int width = 100;
// 区域高度
int height = 100;
// 缩放比, 大于1的时候才生效,小于等于1的情况下不作缩放
int inSampleSize = 2;
Bitmap bitmap = Avif.decode(buffer, x, y, width, height, inSampleSize);

iOS:

#import "AVIFDecoderHelper.h"
#import "UIImage+AVIFDecode.h"

//判断是否是 AVIF 格式以及动图格式
// data为图片NSData类型数据
BOOL isAVIF = [AVIFDecoderHelper isAVIFImage:data];

//解码 AVIF 图片
// data为图片NSData类型数据
UIImage * image = [UIImage AVIFImageWithContentsOfData:data];

/ data为图片NSData类型数据
// 缩小两倍 并指定解码的范围( rect 以原图为基准)
UIImage * image = [UIImage AVIFImageWithContentsOfData:imageData scale:2 rect:CGRectMake(x, y, width, height)];

Android 超大图采样图片库

  1. 安装 subsampling-scale-image-view 和 AVIF SDK
implementation 'com.qcloud.cos:avif:1.1.0'   

implementation 'com.davemorrissey.labs:subsampling-scale-image-view:3.10.0'

// AndroidX 请使用
// implementation 'com.davemorrissey.labs:subsampling-scale-image-view-androidx:3.10.0'
  1. 获取 SubsamplingScaleImageView 控件并注册解码器
SubsamplingScaleImageView subsamplingScaleImageView = findViewById(R.id.subsampling_scale_image_view);

// 设置 AVIF 图片解码器
subsamplingScaleImageView.setBitmapDecoderClass(AvifSubsamplingImageDecoder.class);
subsamplingScaleImageView.setRegionDecoderClass(AvifSubsamplingImageRegionDecoder.class);
  1. 使用 subsampling-scale-image-view 加载图片
    像普通 jpg png 图片那样加载图片即可,请参见 subsampling-scale-image-view 官方文档
// 加载 uri 图片
subsamplingScaleImageView.setImage(ImageSource.uri(uri));

// 加载 assets 图片
subsamplingScaleImageView.setImage(ImageSource.asset("test.avif"));

// 加载 resource 图片
subsamplingScaleImageView.setImage(ImageSource.resource(R.raw.avif));

总结

总之就是数据万象 AVIF SDK 帮您封装了 AVIF 解码器、对 Android iOS 常用的图片库生态也做了封装,真正让您一分钟就能将 AVIF 图片显示到 APP 中。
更加详细的使用说明,请参考:数据万象 Android SDK数据万象 iOS SDK

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,122评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,070评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,491评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,636评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,676评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,541评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,292评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,211评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,655评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,846评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,965评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,684评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,295评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,894评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,012评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,126评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,914评论 2 355

推荐阅读更多精彩内容