「这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战」。
前言
当然,大部分人(包括我)遇到这种问题的第一反应,应该是这样的:
不好意思放错图了,应该是这个:
而现在呢,正好在重构过程中遇到了一点小需求,让我不由得想起这个方案来:
我们先抛开成本、人力、可行性之类的事实不提,难道这套方案真的没有可行性?🤪
貌似还是有那么🤏一丢丢的
这里先不谈瞳孔图片怎么处理,假如真给你搞出图片了,应该怎么处理呢?
在Flutter中,对图片主题色进行分析提取,应该怎么搞:
在原生上,其实已经有很多应用实现了对图片主题色进行提取的操作,这说明方案至少是有实现可能性,可能性还不小;(比如说 android 的 Palette )
那么按照国际惯例,又到了抄原生代码的时候了:
Palette 源码解析
Palette的原理其实并不复杂,跳到启动解析的地方,可以看到其代码量并不多,而且有比较详细注释说明:
根据注释简单总结下步骤:
- 1、缩放压缩图片,没必要整那么大,并根据最后缩放效果同步计算区域之类的信息;
- 2、调用 getPixelsFromBitmap ,解析图片的像素信息,存到数组中;
- 3、构造 ColorCutQuantizer ,计算主题色都是哪些:
- 1、降级颜色,将颜色从RGB888降级为565(反正用不到那么精细)
- 2、根据构造的过滤器,去掉不需要计算分析的色值;
- 3、判断过滤后的色值是否符合要求:
- 1、如果过滤后的色值数量小于设定的最大颜色数量,那么直接返回结果;
- 2、如果过滤后的色值数量大于设定的最大颜色数量,那么调用quantizePixels量化处理色值:
- 1、构造一个名为VBox的类,用于存放最大最小色值等信息,方便获取平均值(说白了就是划分区域,将区域信息放到这个类里面)
- 2、不断寻找色值中点,分割VBox并更新保存的区域信息,直到分割后的VBox数量达到规定的最大颜色数量;
- 3、计算各个VBox中的平均色值,并返回,即可得到主题色;
感觉搞个流程图看起来比较好?
一句话总结:
说白了,其实思路很简单,将图片经过压缩处理后,划分为规定的区块,最后返回各个区块的颜色平均值;
那么接下来要做的事,就是把原生的代码翻译过来
如果单单是翻译,其实问题不大,简单描述下跟Android中做法不一样的部分:
工具类这块问题不大,区别主要是在读取图片数据这块:
在 Android 中,对图片的操作基本通过的是bitmap来做处理;因此读取图片像素信息,可以通过bitmap.getPixels方法来做;
在 Flutter 中,对图片信息的获取,则是通过Image来做的,以一个本地文件为例:需要这么做:
PS :另外发现一个小点,不注意的话,还是能带来了一定困扰的:
在Android中,颜色数值是一个int;
在Dart中,也一样是int:
但是Android,或者说java的int和dart的int,范围是不一样的;
举个例子,同样是红色的FF0000,Dart中FF0000的值是: 4294901760 ,而在java中,红色对应的int值是: -65536
所以在开发Dart的过程中,别被java中熟知的int范围影响到了,要不然就会像我一样,调bug的时候,刚上来看到这个数值那叫一个一脸懵逼;
结语
还是老规矩,国际惯例,附上效果图,列表按区块像素数排序(相当于在图片中的权重了):
首先测试用的图片是这张:
Android的:
Flutter的:
怎么感觉我这个flutter版本的更贴近于主题色呢……这android原生中,黑色区域是第三高的权重,看图片.是这样么?……
不过权重最高的部分,都没什么异议~~~当然,一般我们也不会选权重低的部分当作主题色吧
接下来要做的事,就是分析ImageProvider部分,看下flutter的图片加载流程是什么样的,最后怎么将这个工具类应用到Image小部件上面~
最后呢,首尾呼应,重新回到标题中提到的问题,经过这么一系例处理之后,相信大家已经认可了这套方案并得出了统一的结论:
遇到提这种需求的产品,还是先打一顿比较好,谁打赢了听谁的
更新 :后来发现其实有个库实现了这个效果…………此题完结