在安卓项目中使用gifsicle编辑GIF动图-Android NDK 编译 gifsicle 为可执行文件记录

在安卓项目中使用gifsicle编辑GIF动图-Android NDK 编译 gifsicle 为可执行文件记录,第1张

概述一、前言最近项目中有需要压缩GIF的需求,最开始时试图使用FFmpeg通过降低GIF的分辨率和帧率的来减少GIF文件体积,但实际测试下来,大多数情况下压缩效果并不理想,甚至会出现降低分辨率后导出的GIF甚至比原文件还大的情况。故选择放弃FFmpeg,经过大量的查询资料,发现如果想要压缩GI 一、前言

最近项目中有需要压缩GIF的需求,最开始时试图使用FFmpeg通过降低GIF的分辨率和帧率的来减少GIF文件体积,但实际测试下来,大多数情况下压缩效果并不理想,甚至会出现降低分辨率后导出的GIF甚至比原文件还大的情况。
故选择放弃FFmpeg,经过大量的查询资料,发现如果想要压缩GIF大致有以下几个途径:

参考文章

1.由于 GIF 支持全局调色盘和局部调色盘,在没有局部调色盘的时候会用放在文件头中的全局调色盘。所以对于颜色变化不大的 GIF,可以将颜色放入全局调色盘中,去除局部调色盘。
2. 对于颜色较少的 GIF,将调色盘大小减少,比如从 256 种减少到 128 种等。
3.对于背景一致,画面中有一部分元素在变化的 GIF,可以将多个元素和背景分开存储,然后加上如何还原的信息
4.对于背景一致,画面中有一部分元素在动的 GIF,可以和前面一帧比较,将不动的部分透明化
5.对于帧数很多的 GIF,可以抽取中间部分的帧,减少帧数
6.对于每帧分辨率很高的 GIF,将每帧的分辨率减小

而正如前文所述,抽帧(减小帧率)和减少分辨率有时候效果并不是很好,而且对于图片的质量损耗较大。
对于1,2条途径依然可以使用FFmpeg实现,但是效果也不理想,并且处理起来比较复杂。故剩余的处理方式只剩3和4了。但是正如上文作者所说:“在移动端,除非将 ImageMagick 或者 gifsicle 移植到 iOS&AndroID 上,要实现前面 4 个方法是比较困难的。”
作者提到了两个程序:ImageMagick和gifsicle,经过查询ImageMagick已支持安卓,gifsicle尚未支持。但是ImageMagick目前对于安卓的支持较差,限制较多:

Requires API >= 24 (>= Nougat)
Currently, only arm64-v8a is supported

并且其库过于庞大:


对于我来说只需要它的压缩动图功能,却需要添加这么大的库,性价比过低。
不过如果读者有需要的可以试试,项目地址:ImageMagick
也就是说,现在对于我来说只剩下gifsicle可用,但是gifsicle尚未提供安卓可用版本。
gifsicle项目地址:gifsicle
如何编译 gifsicle 使其在安卓上可用便是本文想要探讨的问题。

二、gifsicle编译方案

原计划是在gifsicle之上使用jni封装使其可以在安卓中调用其接口,但是通过对gifsicle的源码以及issus研究,发现该项目只支持直接编译成可执行文件,且修改较为困难。这也是为什么至今没有移植到安卓上的原因。
github中关于将gifsicle移植成库的讨论
虽说不能直接移植成安卓的 .so 库,但是即使是编译成可执行文件也可以通过

Runtime.getRuntime().exec(cmd, envp)

使用该库,唯一需要注意的是,在安卓10中可能会禁止执行外部可执行库:

AndroID 10 includes the following security changes.
Removed execute permission for app home directory
Untrusted apps that target AndroID 10 cannot invoke exec() on files within the app’s home directory. This execution of files from the writable app home directory is a W^X violation. Apps should load only the binary code that’s embedded within an app’s APK file.
In addition, apps that target AndroID 10 cannot in-memory modify executable code from files which have been opened with dlopen(). This includes any shared object (.so) files with text relocations.

不过经过实际测试,只要是打包进apk中且命名形如 libxxx.so 的可执行文件依旧可以使用。
确定好如何编译后下面就开始编译

三、开始编译1.编译前准备

参考:
想请教关于gifsicle在android上编译的问题
seven332/gifsicle
1.编译环境
我使用的是WSL2 linux+NDK r21b
linux版本如下(因为电脑上正好装着Kali所以就用Kali了,一般用Ubuntu就行)


2.安装依赖
因为编译前需要 automake 生成 config.h 所以需要安装以下依赖(已安装请忽略)

sudo apt-get install autoconf automake libtoolsudo apt-get install libffi-dev

2.下载代码
编译前首先将 gifsicle 下载下来
这里直接 clone 官方仓库:

git clone https://github.com/kohler/gifsicle.git

切进代码目录

cd gifsicle

3.生成 config.h


依据官方文档,首先生成 config

autoreconf -i

根据需要执行 configure ,因为我只需要压缩gif功能,所以其他模块就不需要编译了:

./configure --disable-gifvIEw --disable-gifdiff

此时目录中应该已经生成了一个 config.h 文件。
切记不要执行 make 和 install

4.编写 AndroID.mk 文件
在代码根目录中新建一个 AndroID.mk 文件,内容如下:

LOCAL_PATH := $(call my-dir)include $(CLEAR_VARS)LOCAL_MODulE := gifsicleLOCAL_C_INCLUDES := $(LOCAL_PATH)/includeLOCAL_SRC_fileS := \src/clp.c  \src/fmalloc.c   \src/giffunc.c  \src/gifread.c   \src/gifsicle.c  \src/gifunopt.c   \src/gifwrite.c  \src/merge.c   \src/optimize.c   \src/quantize.c   \src/support.c   \src/xform.c  LOCAL_CFLAGS := -DHAVE_CONfig_H include $(BUILD_EXECUtable)

再新建一个 Application.mk 文件,内容如下:

APP_ABI := allAPP_PLATFORM := androID-16NDK_TOolCHAIN_VERSION := clang

其他东西不需理会,记住 APP_ABI := all 表示需要编译的cpu ABI 版本即可,这里写的是所有版本都编译一份,你也可以指定只编译特定的版本,如 APP_ABI := armeabi-v7a

5.准备编译
将代码目录更名为 jni
否则ndk不会将该项目识别为ndk项目并且编译。
做完上述步骤后的完整目录结构如下:

2.开始编译

1.首先确保你的ndk已经安装并且已配置环境,否则将会

-bash: ndk-build: command not found

安装ndk并配置环境可参考:
VMware安装Ubuntu教程,Linux下搭建Android开发环境
中关于NDK的介绍(AS,SDK等不需要装)

2.切换至 jni 文件夹的上层目录:

cd ../

如图:


3.编译64位的so(arm64-v8a, x86_64)
首先修改 Application.mk 文件的 APP_ABI 为 arm64-v8a, x86_64

vim ./jni/Application.mk

修改后如图:


修改后执行:

ndk-build

如图即为编译成功:


生成的so库在 ./libs 目录下


4.编译32位so(如:armeabi-v7a)
如3中所说,首先修改 Application.mk 文件的 APP_ABI 为 armeabi-v7a


修改 ./jni/config.h 文件

vim ./jni/config.h

找到

#define SIZEOF_UNSIGNED_LONG 8

修改为

#define SIZEOF_UNSIGNED_LONG 4

如图:


切记一定要修改不然会报错如下:


之后执行

ndk-build

即可。

四、使用方法1.复制库

将编译成功的库复制到您的安卓项目文件

项目根目录\app\src\main\jnilibs

下,并且改名为 libgifsicle.so:


一定要记得改名,否则安装时不会被系统复制至可执行文件目录下。

2.使用

代码中已用注释说明各个语句的作用。

val gifsicle = file(file(applicationInfo.nativelibraryDir), "libgifsicle.so")   //可执行文件地址安装后形如:/data/app/com.equationl.myapplication-wZxpZo7IgVPNv3jvY0S8QA==/lib/arm/libgifsicle.soif (!gifsicle.canExecute()) {    Log.e("el", "startCustomizeCompress: can't excute")}val envp = arrayOf("LD_liBRARY_PATH=" + file(applicationInfo.nativelibraryDir))  //设置环境val cmd1 = String.format(Locale.US, "%s -i %s -k 256 -O3 -o %s",        gifsicle.path, file(externalCacheDir, "test.gif").toString(), file(externalCacheDir, "result.gif").toString())  //命令,此处作用为将缓存目录下的 test.gif 更改颜色数为256 按第3级别优化 (详细请自己看 gifsicle 的文档)Log.i("el", "startCustomizeCompress: envp=${envp[0]}\ncmd1=$cmd1")val process = Runtime.getRuntime().exec(cmd1, envp) //开始执行命令try {    if (process.waitFor() != 0) {  //如果执行成功会返回 0,不成功返回非0        Log.e("el", "startCustomizeCompress: running error process.waitFor() != 0")    }    else {        Log.i("el", "Success!")    }} catch (e: InterruptedException) {    e.printstacktrace()}

关于 gifsicle 的使用方法请自行查看官方文档

@equationl 原创
@email:[email protected]

总结

以上是内存溢出为你收集整理的在安卓项目中使用gifsicle编辑GIF动图-Android NDK 编译 gifsicle 为可执行文件记录全部内容,希望文章能够帮你解决在安卓项目中使用gifsicle编辑GIF动图-Android NDK 编译 gifsicle 为可执行文件记录所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/web/1055906.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-05-25
下一篇 2022-05-25

发表评论

登录后才能评论

评论列表(0条)

保存