布景

最近项目上有接入腾讯libpag 用作动效完结,至此项目上现已包括了三种格式的动效,svga,lottile,pag。而事务需求是客户端要可以支持多种格式的动效处理。 因而事务代码完结经常是下面的逻辑


when(图片类型){
    "svga"->{
        处理svga的逻辑
    }
    "lottile"->{
        处理了lottile的逻辑
    }
    "pag"->{
        处理pag动效的逻辑
    }
    else->{
        处理为普通图片
    }
}

这样的事务逻辑代码散布在项目的各个地方,运用的运用不只需求重复的处理对应的事务逻辑,也不利于维护。而且腾讯 libpag 的 PagView 作为ui的出现, 支持的是从本地文件途径或者直接设置一个 PAGComposition 方针到 PagView 进行显现,并不对文件的下载进程进行处理。 对应文件的下载功用天然落在了开发者身上,假如为了接入libpag 而自己去完结一套 下载缓存的功用功用巨大且复杂,且整个进程需求研发、测试的完全介入,本钱相对较高。运用项目上已有的下载计划天然是一个不错的挑选。 Glide 作为一个老练安稳的图片加载框架,具有图片加载和文件下载的能力。并在内部完结了多级缓存的机制,与列表错位的处理。

将 libpag 与 Glide 进行结合不只效果安稳而且图片加载的方法不会进行改动,运用者也不需求额外的学习本钱。

方针与设计完结

本次扩展主要有两个方针

  1. 可以运用Glide 加载显现到 PagView
  2. 做到图片加载的时分不需求进行事务区别,让 Glide 像加载普通图片一样加载pag

计划完结:

方针一:

Glide 数据加载大致有 数据加载-> 解码 -> 转码 三个流程 现在Glide 会将网络数据加载成InputStream 流 咱们需求扩展的是当检测到stram 是 PAG 时将流解码成文件,再对文件进行转码,转码结果是 PagView 需求的 PAGComposition 。

方针二

Glide 默认加载出的方针是Drawable,然后直接将Drawable方针设置给ImageView 运用,而 PagView 需求的是一个 PAGComposition 。为此 可以自定义一个Drawable 方针 PAGFileDrawable 内部包括PAGComposition 对下。 可是 PagView 并不是直接承继自ImageView 并不能直接运用Drawable方针。为了到达运用时不区别详细的资源类型的目的,咱们封装一个ViewGroup AutoAnimationView,AutoAnimationView 内部包括ImageView和PagView 当加载结果是 PAGFileDrawable 时显现 PagView 隐藏 ImageView 反之显现 ImageView 隐藏 PagView

代码完结

说了这么多,主角总算来了。测验让chatGpt 帮我完结上面的逻辑

  1. 先进行下衬托 看看gpt能不能扩展,显然gpt知道怎样扩展,并给出一段wep解码的示例

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片

  1. 紧接着咱们让gpt依照 添加一个解码器

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片

public class PagDecoder implements ResourceDecoder<InputStream, File> {
    private final Context context;
    public PagDecoder(Context context) {
        this.context = context;
    }
    @Override
    public Resource<File> decode(InputStream source, int width, int height, Options options) throws IOException {
        // 将输入流保存为本地文件
        File file = saveInputStreamToFile(source);
        // 返回本地文件的Resource方针
        return new FileResource(file);
    }
    @Override
    public boolean handles(InputStream source, Options options) throws IOException {
        // 判别输入流是否为PAG类型
        return isPag(source);
    }
    private boolean isPag(InputStream source) {
        // 判别输入流是否为PAG类型的逻辑
        // 这儿仅仅一个示例,需求依据实际情况自行完结
        return true;
    }
    private File saveInputStreamToFile(InputStream input) throws IOException {
        // 创立一个临时文件来保存输入流
        File outputDir = context.getCacheDir();
        File outputFile = File.createTempFile("temp", ".tmp", outputDir);
        // 运用流的方法将输入流写入文件
        OutputStream output = new FileOutputStream(outputFile);
        byte[] buffer = new byte[4 * 1024]; // 4KB
        int bytesRead;
        while ((bytesRead = input.read(buffer)) != -1) {
            output.write(buffer, 0, bytesRead);
        }
        output.flush();
        output.close();
        return outputFile;
    }
}
  1. 显着看到这儿的isPag 直接返回了true 这个不是咱们想要的,于是咱们又问gpt 怎样判别,图片的类型

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片
4. 重写方才的类

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片
由于gpt 完结是java 我又让它把代码转换成kotlin

class PagDecoder(private val context: Context) : ResourceDecoder<InputStream, File> {
    override fun decode(source: InputStream, width: Int, height: Int, options: Options): Resource<File>? {
        // 将输入流保存为本地文件
        val file = saveInputStreamToFile(source)
        // 返回本地文件的Resource方针
        return FileResource(file)
    }
    override fun handles(source: InputStream, options: Options): Boolean {
        // 判别输入流是否为PAG类型
        return isPag(source)
    }
    private fun isPag(source: InputStream): Boolean {
        // 判别输入流是否为PAG类型的逻辑
        // 这儿仅仅一个示例,需求依据实际情况自行完结
        val header = ByteArray(4)
        try {
            source.read(header)
        } catch (e: IOException) {
            e.printStackTrace()
        }
        return header.contentEquals(byteArrayOf(0x50, 0x41, 0x47, 0x00))
    }
    @Throws(IOException::class)
    private fun saveInputStreamToFile(input: InputStream): File {
        // 创立一个临时文件来保存输入流
        val outputDir: File = context.cacheDir
        val outputFile = File.createTempFile("temp", ".tmp", outputDir)
        // 运用流的方法将输入流写入文件
        val output: OutputStream = FileOutputStream(outputFile)
        val buffer = ByteArray(4 * 1024) // 4KB
        var bytesRead: Int
        while (input.read(buffer).also { bytesRead = it } != -1) {
            output.write(buffer, 0, bytesRead)
        }
        output.flush()
        output.close()
        return outputFile
    }
}

5.转码器完结

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片

这一次gpt并没有完结对应的转码器 而是完结了一个解码器,因而我再次强调强调了一遍是转码器。而gpt 也认识到了他的过错。就不经验它了

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片

class PagFileTranscoder : ResourceTranscoder<File, PAGFile> {
    override fun transcode(toTranscode: Resource<File>, options: Options): Resource<PAGFile>? {
        // 获取文件途径
        val filePath = toTranscode.get().path
        // 运用 PAGFile.Load 方法将文件转换成 PAGFile 方针
        val pagFile = PAGFile.Load(filePath)
        // 返回 PAGFile 方针的 Resource 方针
        return PagFileResource(pagFile)
    }
    override fun getTranscodeOptions(options: Options): Options {
        return options
    }
    class PagFileResource(val pagFile: PAGFile) : Resource<PAGFile> {
        override fun getResourceClass(): Class<PAGFile> {
            return PAGFile::class.java
        }
        override fun get(): PAGFile {
            return pagFile
        }
        override fun getSize(): Int {
            return pagFile.getData().size
        }
        override fun recycle() {
            // 不需求进行资源收回操作
        }
    }
}

显着可以看到的是转码的时分 是都一切文件执行的。而咱们想转码的文件是PAG 动效资源。于是

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片
一起让gpt 删去一些不必要的代码之后最终的代码是

class PagFileTranscoder(private val context: Context) : ResourceTranscoder<File, PAGFile> {
    override fun transcode(
        toTranscode: Resource<File>,
        options: Options
    ): Resource<PAGFile>? {
        // 获取文件途径
        val filePath = toTranscode.get().path
        // 读取文件头部信息,用于判别文件类型
        val header = ByteArray(8)
        FileInputStream(filePath).use { inputStream ->
            inputStream.read(header)
        }
        // 判别文件是否是 PAG 类型的文件
        if (isPAGFile(header)) {
            // 运用 PAGFile.Load 方法将文件转换成 PAGFile 方针
            val pagFile = PAGFile.Load(filePath)
            // 返回 PAGFile 方针的 Resource 方针
            return SimpleResource(pagFile)
        }
        return null
    }
    private fun isPAGFile(header: ByteArray): Boolean {
        // 判别文件头部信息是否与 PAG 文件的头部信息相同
        return header[0] == 'P'.toByte() &&
                header[1] == 'A'.toByte() &&
                header[2] == 'G'.toByte() &&
                header[3] == 'F'.toByte()
    }
}

然后我自己完结简单完结了一些封装

class PAGViewTarget(
    private val view: PAGView
) : CustomViewTarget<PAGView, PAGFile>(view) {
    override fun onResourceLoading(placeholder: Drawable?) {
        view.stop()
    }
    override fun onResourceCleared(placeholder: Drawable?) {
        view.stop()
    }
    override fun onResourceReady(resource: PAGFile, transition: Transition<in PAGFile>?) {
        view.composition = resource
        view.setRepeatCount(50)
        view.play()
    }
    override fun onLoadFailed(errorDrawable: Drawable?) {
    }
}
fun RequestBuilder<PAGFile>.into(pagView:PAGView){
    into(PAGViewTarget(pagView))
}
fun RequestManager.asPAGFile():RequestBuilder<PAGFile>{
    return `as`(PAGFile::class.java)
}

在Application中加解码器和转码器注册

Glide.get(this).registry.append(InputStream::class.java, File::class.java, PagDecoder(this))
    .register(
        File::class.java,
        PAGFile::class.java,
        PagFileTranscoder()
    )

在页面当中进行运用

Glide.with(this).asPAGFile().load("https://github.com/Tencent/libpag/blob/main/assets/data_video.pag?raw=true").into(pagView)

然后加载失败了,经过排查 原来是gpt 判别文件类型出错了。

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片

至此 扩展Glide 加载 pag 图片的功用现已完结啦

至于方针二的完结 就不粘贴与gpt的聊天内容了。

最终结果

这儿直接献上 最终整理的代码 和 效果图 刚兴趣的小伙伴可以直接下载代码运行测验

用chatGpt 扩展Glide支持腾讯libpag PAG 动效图片

代码地址: github.com/xiaolutang/…
留意demo上的pag 地址是腾讯官方 github 地址 访问要挂vpn

运用chatgpt的感触

当前chatgpt 关于一些深入的事务场景还没方法具有足够的理解能力。并不能直接输出可用代码。乃至经常输出过错的代码。可是这并不妨碍gpt 未来对程序员作业的影响。整体而言 关于代码的落地 需求咱们不断的引导gpt进行批改。当与gpt 交流的次数足够多的是他就可以依照你的要求产生你想要的东西(可是这个交流进程可能极其苦楚,某些时分 你明明现已纠正了可是gpt 仍是会依照过错的内容进行输出)。 关于个人而言,在作业中有用的运用gpt 可以进步个人的开发效率,每个人都应该具有自己独立的人工智能帮手,经过训练这个帮手让人工智能更加了解你的作业习气,然后进步个人的开发效率。