图像格式篇可以从网络加载点图的吗

你拿手机刷着刷着,突然手滑点开一张图,这图向上无限高,向下无限深,向左无限远,向右无限远,这图是什么?

是点9图。🤣

大家好,我是来颠覆你对点9图固有认知的星际码仔。

点9图几乎在每个Android工程中都或多或少地有用到,而切点9图也可以说是每个Android开发者必备的传统艺能了,但今天我们要分享的主题估计各位平时比较少接触到,就是——从网络加载点9图。

为了讲好这个主题,我们会从点9图的基础知识出发,比较网络加载方式与常规用法的区别,然后分别给出一个次优级和更优级的解决思路,可以根据你们当前项目的实际情况自由选取。

照例,先给出一张思维导图,方便复习:

其典型的一个应用就是IM中的聊天气泡框,气泡框的宽高会随着我们输入文本的长短而自适应拉伸,但气泡框资源本身并不会因拉伸而失真。

这么神奇的效果是怎么实现的呢?

答案是:四条黑线。

可拉伸区域由左侧及顶部一条或多条黑线来定义,左侧的黑色边框定义了纵向拉伸的区域,顶部的黑色边框定义了横向拉伸的区域,拉伸的效果是通过复制区域内图片的像素来实现的。

可以看到,由于可拉伸区域选择的都是比较平整的区域,而没有覆盖到四周的圆角,因此图片无论怎么纵向或横向拉伸,四周的圆角都不会因此而变形失真。

可绘制区域由右侧及底部的各一条黑线来定义,称为内边距线。如果没有添加内边距线,视图内容将默认填满整个视图区域。

而如果添加了内边距线,则视图内容仅会在右侧及底部的黑线所定义的区域内显示,如果视图内容显示不下,则图片会拉伸至合适的尺寸。

但这种情况在改成了从网络加载点9图之后有所变化。

问题在于,即使强大如Glide,对于从网络加载点9图的这种场景,也没有做很好的适配,以至于我们加载完图片之后会发现...

完!全!没!有!拉!伸!效!果!

要理解这背后的原因,我们需要把目光转移到一个原本在打包过程中常常被我们忽视的角色——AAPT。

AAPT即Android Asset Packaging Tool,是用于构建*.apk文件的Android资源打包工具,默认存放在Android SDK的build-tools目录下。

尽管我们很少直接使用AAPT工具,但其却是.apk文件打包流程中不可或缺的重要一环,具体可参照下面的.apk文件详细构建流程图。

而常规用法下的点9图之所以能正常工作,也离不开打包时,AAPT对于包含点9图在内的PNG格式图片的预处理。

那么,AAPT的预处理具体都做了哪些事情呢?

首先,我们要了解的是,在Android的世界里,存在着两种不同形式的点9图文件,分别是“源类型(source)”和“已编译类型(compiled)”。

源类型就是前面所提到的,使用了包括Draw 9-patch在内的点9图制作工具所创建的、四周带有1像素宽黑色边框的PNG图片。

而已编译类型指的是,把之前定义好的点九图数据(可拉伸区域&可绘制区域等)写入原先格式的辅助数据块后,把四周的黑色边框抹除了的PNG图片。

这里稍微提一下PNG图片的文件格式。

在文件头之外,PNG图片使用了基于“块(chunk)”的存储结构,每个块负责传达有关图像的某些信息。

块有关键块或辅助块两种类型,关键块包含了读取和渲染PNG文件所需的信息,必不可少。而辅助数据块则是可选的,程序在遇到它不理解的辅助块时,可以安全地忽略它,这种设计可以保持与旧版本的兼容性。

点九图数据所放入的,正是一个tag为“npTc”的辅助数据块。

AAPT在打包过程中对点9图的预处理,其实就是将点9图从源类型转换为已编译类型的过程,也只有已编译类型的点9图才能被Android系统识别并处理,从而达到根据视图内容自动调整图片大小的效果。

而直接从网络加载的点9图则缺少这个过程,我们实际拿到的是没有经过AAPT预处理的源类型,Android系统就只会把它当普通的PNG格式图片一样处理,因此展示时会有残留在四周的黑色边框,并且当视图内容过大时,图片就会因为不合理拉伸而产生明显的失真。

明白了这一层的原理之后,我们也就有了一个次优级别的解决思路,也即:

AAPT同时也是一个命令行工具,其在打包过程中参与的多项工作都可以通过命令行来实现。

其中就包括对PNG格式图片的预处理。

于是,具体可操作的步骤也很清晰了:

这样做还有一个好处就是,AAPT命令行工具会校验源类型点9图的规格,如果不合规就会报错并给出原因提示,这样就可以在生产端时就保证产出点9图的合规性,而不是等到展示的时候才发现有问题。

命令行如下:

[]表示是可选的完整命令或参数。

这个过程还需保证不会因流量压缩而将图片转为Webp格式,或者造成“npTc”的辅助数据块丢失。

这里主要涉及到2个问题:

这2个问题都可以从Android SDK源码中找到答案。

关于问题1,我们可以从点9图的常见应用场景,即设为视图控件背景的API入手,从View#setBackground方法一路深入直至BitmapFactory#setDensityFromOptions方法,就可以看到:

Bitmap#getNinePatchChunk方法返回的是一个byte数组类型的数据,从方法名就可以看出其正是关于点九图规格的辅助块数据:

NinePatch#isNinePatchChunk方法是一个Native函数,我们等到后面深入点九图Native层结构体时再展开讲:

而关于问题2,我们可以通过查找对Bitmap#getNinePatchChunk方法的引用,在Drawable#createFromResourceStream方法中找到一个参考例子:

可以看到,它是通过在判断NinePatchChunk数据不为空后,构建了一个NinePatchDrawable来告诉系统以点9图的形式正确处理这张图的。

于是我们可以得出结论,客户端要做的额外处理,就是在拿到已编译类型的点9图并构建为Bitmap后:

先调用Bitmap#getNinePatchChunk方法尝试获取点9图数据

再通过NinePatch#isNinePatchChunk方法判断是不是点9图数据。

如果是点9图数据,则利用这个点9图数据构建一个NinePatchDrawable

如果不是,则构建一个BitmapDrawable。

示例代码如下:

这样就满足了吗?并没有。方案本身虽然可行,但让一向习惯可视化界面操作的设计组同事执行命令行,实在是有点太为难他们了,并且每次产出资源后都要用AAPT工具处理一遍,也确实有点麻烦。

话说回来,命令行工具的底层肯定还是依赖代码来实现的,那有没有可能在客户端侧实现一套与AAPT工具一样的逻辑呢?这就引出了我们一个更次优级别的解决思路,也即:

透过上一个方案我们可以了解到,最关键的地方还是那个byte数组类型的点九图数据块(NineChunk),如果我们能知道这个数据块里面实际包含什么内容,就有机会在在客户端侧构造出一份类似的数据。

上一个方案中提到的NinePatch#isNinePatchChunk方法就是我们的突破点。

接下来,就让我们进入Native层查看isNinePatchChunk方法的源码实现吧:

可以看到,在isNinePatchChunk方法内部实际是将传入的byte数组类型的点9图数据转为一个Res_png_9patch类型的结构体,再通过一个wasDeserialized的结构变量来判断是不是点9图数据的。

这个Res_png_9patch类型的结构体内部是这样的:

很明显,这个结构体就是用来存储点9图规格数据的,我们可以根据该结构体的源码和注释梳理出每个变量的含义:

根据该结构体注释中的描述,这个结构体是用于指定如何将图像分割成多个部分以进行缩放的,其中:

以该结构体注释中的例子来说,mDivX,mDivY,mColor分别如下:

我画了一张示意图,应该会更方便理解一点:

这几个结构体变量所描述的,不正是我们源类型的点9图四周所对应的那些黑色边框的位置吗?

那么,现在我们只需要在Java层定义一个与Res_png_9patch结构体的数据结构一模一样的类,并在填充关键的变量数据后序列化为byte数组类型的数据,就可以作为NinePatchDrawable构造函数的参数了。

这里只给出使用层的示例代码:

NinePatchChunk类即为前面说的在Java层定义的类,并提供了几个静态方法用于创建NinePatchDrawable,其在内部会去检测传入的Bitmap实例属于哪种类型:

NinePatch即为已编译类型的点9图,RawNinePatch即为源类型的点9图,源类型是通过PNG图片4个角像素是否为透明且是否包含黑色边框判断的。

THE END
0.Image及其属性image支持哪些类型的图片格式在这个示例中,我们创建了一个Image组件,并设置了其宽度、高度和填充方式。objectFit属性用于设置图片的填充效果,常见的值有cover、contain、fill等。 支持的图片格式 ArkUI的Image组件支持多种图片格式,包括PNG、JPG、BMP、SVG、GIF和HEIF。开发者可以根据实际需求选择合适的图片格式。需要注意的是,不同格式的图片在加jvzquC41dnuh0lxfp0tfv8mwcpmzwjsazwgo1jwvkerf1mjvckrt1:9:27796<
1.组件的使用鸿蒙image支持哪些类型的图片格式设置图片缩放类型 图片插值 设置图片重复样式 设置图片渲染模式 设置图片解码尺寸 为图片添加滤镜效果 同步加载图片 事件调用 开发者经常需要在应用中显示一些图片,例如:按钮中的icon、网络图片、本地图片等。在应用中显示图片需要使用Image组件实现,Image支持多种图片格式,包括png、jpg、bmp、svg、gif和heif,不支持apngjvzquC41dnuh0lxfp0tfv8~g|workwlzkp5bt}neng5eg}fknu526B<8;:;1
2.图片编解码支持的格式有哪些图片处理(Image)拍照和图片Image或者ImageSpan传入一个string类型的路径时无法加载图片 Image组件如何读入沙箱内的图片 如何实现事件透传 Text组件设置maxLines后如何确定文本是否被隐藏 如何实现类似keyframes的效果 外部容器Stack能否满足适应内部容器组件的圆角等样式 Stack布局设置Alignment.Bottom没有生效 布局是否支持css里的calc(100vh -jvzquC41fg|fnxugt0nvc€jk0eun1ltpuwsft8hp1fud1qftoqtzq|2hcsy0hjvu/ksbin27
3.ps支持哪些格式?ps中jpg/jpeg/jpeg2000的区别介绍photoshop教程大型文档格式(PSB) PSD的进阶版本,PSD虽然厉害,但不能存储2GB以上的图片,而且它的色深也被局限在了8位/通道,如果你的图片超过上述限制,可以选择PSB格式文件,它支持4GB以上图片和8位以上色深,其他功能与PSD一致。 PSB格式是Photoshop的大型文档格式,可支持最高达到300000像素的超大图像文件。他支持photoshop所有功能,可jvzquC41yy}/lk:30pku1ymqvqyiqy49:9=447mvon
4.Image组件使用详解Image 组件用于添加图片; 支持的图片格式:png、jpg,别的不太了解,没做做过多测试; 不支持图片格式:android 环境下不支持gif格式图片,显示一个空白,这点值得注意,所以在模拟数据加载动画的时候,android 环境下是不能实现的,目前解决办法是把一个gif格式的图片切割成很多分,间隔时间替换图片路径实现这么一个动态的效jvzquC41dnuh0lxfp0tfv8qqxgekunw1ctzjeuj1fgzbkux17493997;
5.Image(基础组件)image支持哪些类型的图片格式Image为图片组件,常用于在应用中显示图片。Image支持加载PixelMap、ResourceStr和DrawableDescriptor类型的数据源,支持png、jpg、jpeg、bmp、svg、webp、gif和heif类型的图片格式。 说明: 该组件从API Version 7开始支持。后续版本如有新增内容,则采用上角标单独标记该内容的起始版本。 jvzquC41dnuh0lxfp0tfv8xjwfgpuqfpDDW0c{ykenk0fnyckny03=644:943
6.又拍云文档中心如上列表可以看出,当 Accept 请求头里面如果有image/webp字段,则说明客户端支持 WebP 解码。 2.CDN 如何实现实时图片格式转换? 针对用户源站并非 WebP 格式图片的时,CDN 层需要支持将原图图片的实时转换为 WebP 格式副本,这个在 CDN 层面是无缝支持的。流程是这样的: jvzq<84fqey/wy~wp0ipo8hfp1ipponi1
7.IMAGE函数=IMAGE(source, [alt_text], [sizing], [height], [width]) IMAGE 函数采用以下参数: source图像文件的 URL 路径(使用“https”协议)。 必需。 支持的文件格式包括 BMP、JPG/JPEG、GIF、TIFF、PNG、ICO 和 WEBP(Web 和 Android 上不支持 WEBP)。 jvzquC41uwvqq{y0okisq|thv0ipo8j/et0qokkeg5jojlg/'K6'A<'DF+F8.>7'D6.9n634;=6/>j74/:g4j2d;fg.3m>35f;2h>i7
8.百度人脸识别使用指南私有化部署接口文档image是string图片信息(总数据大小应小于10M),图片上传方式根据image_type来判断。两张图片通过json格式上传,格式参考表格下方示例 image_type是string图片类型 BASE64:图片的base64值,base64编码后的图片数据,编码后的图片大小不超过2M; FACE_TOKEN: 人脸图片的唯一标识,调用人脸检测接口时,会为每个人脸图片赋予一个唯jvzquC41vqvzww3xkr5jpmjz0rnq1qjnr1gsvrhng1823@3jvor
9.关于cv::imread读取图片类型的初探[通俗易懂]cv::imread支持哪些常见的图片格式? 如何判断cv::imread是否成功读取了图片? cv::imread读取图片时如何指定读取模式? 大家好,又见面了,我是你们的朋友全栈君。 关于cv::imread读取图片类型的初探 问题来源 环境 首先生成单通道和三通道的png图片 cv::imread函数及其参数 不同参数读取rgb图像 不同参数读取单通道图jvzquC41enuvf7ygpekov7hqo1jfxnqqrgx0c{ykenk04:;;27:
10.Python技巧之实现批量统一图片格式和尺寸python编辑能力:不同的图片格式支持不同的编辑功能。通过将图片转换为支持所需编辑功能的格式,可以更轻松地进行编辑工作。 如果我们需要把图片转换成文件,用Python学习的知识是不是能实现呢? Python模块之Image的应用示例 1.首先需要导入需要的图像库: 1 importImage jvzquC41yy}/lk:30pku1jwvkerf1;=565=/j}r