安装字体怎么在wordpress,seo排名如何优化,网站 68,重庆关键词搜索排名OpenAtom OpenHarmony#xff08;以下简称“OpenHarmony”#xff09;提供了Image组件支持GIF动图的播放#xff0c;但是缺乏扩展能力#xff0c;不支持播放控制等。今天介绍一款三方库——ohos-gif-drawable三方组件#xff0c;带大家一起玩转GIF的数据渲染#xff0c;搞…OpenAtom OpenHarmony以下简称“OpenHarmony”提供了Image组件支持GIF动图的播放但是缺乏扩展能力不支持播放控制等。今天介绍一款三方库——ohos-gif-drawable三方组件带大家一起玩转GIF的数据渲染搞定GIF动图的各种需求。
效果演示 本文将从5个小节来带领大家使用ohos-gif-drawable这一款三方库其中1、2、3这3个小节主要介绍了ohos-gif-drawable的核心能力、GIF软解码和GIF绘制。4和5小节主要是扩展讨论如何添加滤镜效果和软解码遇到的耗时问题。 1.GIF的文件格式理论基础
工欲善其事必先利其器。首先我们需要为自己打下理论基础。了解GIF的数据格式为后续解码GIF提供理论支持。 通过学习GIF的文件格式我们对于GIF的组成格式有了一定的了解并且有助于理解后面GIF的解码。
在开始介绍之前我想让大家了解一下整体的结构思路如下图 其中gifuct-js三方库主要完成了解码的工作。
ohos-gif-drawable三方库则是在gifuct-js的三方库之上进行了封装。并结合了OpenHarmony的Canvas绘制能力达到了播放和控制GIF的能力。
2.GIF软解码gifuct-js三方库介绍
GIF解码我们使用了gifuct-js这个库它是一个纯JavaScript的GIF解码库。首先我们需要了解基础用法。
2.1 参考样例将一个文件ArrayBuffer转换为GIF解码后的帧数据数组。
//javascript
var gif parseGIF(arraybuffer)
var frames decompressFrames(gif, true)2.2 由于OpenHarmony的Image生成PixelMap需要的数据是BGRA数据而2.1生成的frames所有数组中的patch字段则是RGBA数据所以我们需要使用
//javascript
var gif parseGIF(arraybuffer)
var frames decompressFrames(gif, false)然后将frame目前还未生成的patch字段数据通过generatePatch 函数将RGBA的数据更换为BGRA即可如下代码所示
//javascript
const generatePatch image {const totalPixels image.pixels.lengthconst patchData new Uint8ClampedArray(totalPixels * 4)for (var i 0; i totalPixels; i) {const pos i * 4const colorIndex image.pixels[i]const color image.colorTable[colorIndex] || [0, 0, 0]patchData[pos] color[2] // BpatchData[pos 1] color[1]// GpatchData[pos 2] color[0] // RpatchData[pos 3] colorIndex ! image.transparentIndex ? 255 : 0//A}return patchData
}generatePatch函数在这里会根据颜色表colorTable和基于颜色表的图像数据pixels以及透明度transparentIndex生成BGRA格式的patchData这个数据和Canvas中getImageData获取的ImageData数据是一致的都是Uint8ClampedArray类型可以直接使用putImageData让canvas绘制。
最后生成的patchData赋值给Frame的patch字段。
这里我们并没有直接使用Canvas的putImageData直接绘制。为了提升扩展性我们使用了Image的能力来生成PixelMap这样处理为后续滤镜效果提供了可能也方便后续绘制流程。
好了到这里我们就基本上把gifuct-js库的基础使用简单介绍完了。
如何使用GIFohos-gif-drawable三方库的介绍。
我们先来看看整个ohos-gif-drawable组件的模型图通过模型图我们可以看到用户只要关注GIFComponent组件和GIFComponent.ControllerOptions配置参数以及控制参数autoPlay和resetGif即可非常简单 支持的功能列表如下
● 支持播放GIF图片。 ● 支持控制GIF播放/暂停。 ● 支持重置GIF播放动画。 ● 支持调节GIF播放速率。 ● 支持监听GIF所有帧显示完成后的回调。 ● 支持设置显示大小。 ● 支持7种不同的展示类型。 ● 支持设置显示区域背景颜色。
如何使用ohos-gif-drawable
首先需要使用npm下载ohos-gif-drawable三方库
npm install ohos/ohos-gif-drawable --save接下来我们需要配置一个worker给gifuct-js解码使用。
配置worker在应用工程的entry/src/main/ets/pages目录下新建workers文件夹并且创建文件 gifParseWorker.ts 文件内容如下
import arkWorker from ohos.worker;
import { handler } from ohos/ohos-gif-drawable/src/main/ets/components/gif/worker/GifWorker
// handler封装了子线程逻辑但worker目前只能在entry中进行创建arkWorker.parentPort.onmessage handler;然后在entry目录的build-profile.json5文件中添加如下内容
buildOption: {
sourceOption: {
workers: [ ./src/main/ets/pages/workers/gifParseWorker.ts
]
}
},到这里我们worker就配置好了。
下面就到了正式使用环节我们只要在UI界面需要的地方写上自定义控件GIFComponent然后传入GIFComponent.ControllerOptions,gifAutoPlay,gifReset这三个参数就能控制gif动画。
import { GIFComponent, ResourceLoader } from ohos/ohos-gif-drawable
// gif绘制组件用户属性设置
State model:GIFComponent.ControllerOptions new GIFComponent.ControllerOptions();
// 是否自动播放
State gifAutoPlay:boolean true;
// 重置GIF播放每次取反都能生效
State gifReset:boolean true;
// 在ARKUI的其他容器组件中添加该组件
GIFComponent({model:$model, autoPlay:$gifAutoPlay, resetGif:this.gifReset})举个简单的例子说明一下
// 创建worker
let worker new ArkWorker.Worker(entry/ets/pages/workers/gifParseWorker.ts, {type: classic,name: loadUrlByWorker})
// 关闭动画
this.gifAutoPlay false;
// 销毁上一次资源
this.model.destroy();
// 新创建一个modelx用于配置用户参数
let modelx new GIFComponent.ControllerOptions()
modelx
// 配置回调动画结束监听和耗时监听
.setLoopFinish((loopTime) {
this.gifLoopCount;
this.loopHint 当前gif循环了 this.gifLoopCount 次,耗时 loopTime ms
})
// 设置组件大小
.setSize({ width: this.compWidth, height: this.compHeight })
// 设置图像和组件的适配类型
.setScaleType(this.scaleType)
// 设置播放速率
.setSpeedFactor(this.speedFactor)
// 设置背景
.setBackgroundColor(Color.Grey)
// 加载网络图片,getContext(this)中的this指向page页面或者组件都可以ResourceLoader.downloadDataWithContext(getContext(this), { url: https://pic.ibaotu.com/gif/18/17/16/51u888piCtqj.gif!fwpaa70/fw/700 }, (sucBuffer) {
// 网络资源sucBuffer返回后处理
modelx.loadBuffer(sucBuffer, () { console.log(网络加载解析成功回调绘制)
// 开启自动播放
this.gifAutoPlay true;
// 给组件数据赋新的用户配置参数达到后续gif动画效果
this.model modelx; }, worker)}, (err) {
// 用户根据返回的错误信息进行业务处理(展示一张失败占位图、再次加载一次、加载其他图片等)
})这里ResourceLoader内置了加载网络资源GIF本地工程资源GIF和本地路径资源GIF文件数据的能力。
如果你已经有了GIF文件的arraybuffer数据也可以直接调用modelx.loadBuffer(buffer: ArrayBuffer, readyRender: (err?) void, worker: any)进行GIF播放。
甚至你已经生成了GIF解析数据比如调用了2.2中的解码代码那么你也可以直接调用modelx.setFrames(images?: GIFFrame[])来进行gif播放。
1.控制GIF的播放与暂停
this.gifAutoPlay true 开启动画
this.gifAutoPlay false 暂停动画组件内部会监听该参数的变化用户只要改变值即可达到控制效果
2. 重置GIF的播放
this.gifReset !this.gifReset 每次变化都会重置gif播放。由于重置不需要状态管理所以组件内监听到数据变化就会重置gif播放
3. 设置GIF动画播放速度
let modelx new GIFComponent.ControllerOptions()
modelx.setSpeedFactor(2)// 将速率提升到2倍调用setSpeedFactor(speed: number)即可调整播放速度speed 为对比原始速率的乘积因子比如设置0.5即为原始速率的0.5倍设置为2即为原始速率的2倍。
4. 监听GIF动画播放回调比如第一次动画结束和获取动画实际播放总时长
let modelx new GIFComponent.ControllerOptions()
modelx.setLoopFinish((loopTime?) {
// loopTime为GIF动画一周期耗时回调时间为GIF动画一周期结束时间节点
})调用setLoopFinish(fn: (loopTime?) void)可以通过回调得到GIF动画运行一周期耗时和一周期结束时间节点。
5. 显示GIF任意一帧
let modelx new GIFComponent.ControllerOptions()
modelx.setSeekTo(5) // 直接展示该gif第5帧图像调用setSeekTo(gifPosition: number)可以直接展示该gif的某一帧图像。
到这里ohos-gif-drawable三方库的主要能力都介绍完了是不是很简单呢
6. 适配组件的大小
let modelx new GIFComponent.ControllerOptions()modelx.setScaleType(ScaleType.FIT_CENTER) // 将图像缩放适配组件大小调用setScaleType(scaletype: ScaleType)可以将图像和组件大小进行适配。
目前支持的类型如下图所示
GIFComponent.ScaleType 为什么要配置worker
在具体实践过程中我们会发现当我们按下解码按钮的时候主界面会有一点卡顿的情况。特别是大的GIF文件进行解码的时候效果更明显。这是因为我们在主线程中进行了CPU的密集型计算这是一个耗时且占用CPU的操作。主线程中是不能执行耗时操作的。但是JavaScript只有一个线程啊那么解码这一块操作该如何处理会比较好呢带着疑惑我去查阅了资料发现JavaScript虽然属于单线程环境。但是通过引入Worker的能力引入子线程worker可以实现JavaScript的“多线程”技术。
OpenHarmony如何在子线程中处理耗时任务
为了争取良好的用户体验我们需要将耗时操作封装至子线程中。
这里简单描述一下worker的能力
能够让主页面运行的JavaScript线程中加载运行另外单独的一个或者多个JavaScript线程但是它的多线程编程能力区别于传统意义上的多线程编程。主线程和Worker线程之间不会共享任何作用域和资源他们的通信方式是基于事件监听机制的 message。
接下来我们参考OpenHarmony文档下的worker能力
1. OpenHarmony环境下Worker的API接口列表
2. Worker的使用简单案例
经过了解之后我们可以把解码的耗时封装到worker中处理避免主线程耗时操作占用CPU导致卡顿问题。提升用户体验。
这也是使用ohos-gif-drawable三方库需要配置worker的原因。
扩展部分
GIF的滤镜效果
1. 灰白滤镜
//javascript
// 重点代码更改 let avg (color[0] color[1] color[2]) / 3patchData[pos] avg;patchData[pos 1] avg;patchData[pos 2] avg;patchData[pos 3] colorIndex ! image.transparentIndex ? 255 : 0;2. 反转滤镜
//javascript
// 重点代码更改patchData[pos] 255 - color[0];patchData[pos 1] 255 - color[1];patchData[pos 2] 255 - color[2];patchData[pos 3] colorIndex ! image.transparentIndex ? 255 : 0;3. 高级滤镜效果
假设我们这边已经拿到了patch: Uint8ClampedArray像素数据这里我需要先将其变换为一张PixelMap数据参考GIFComponent中patch数据转换为PixelMap的代码。
//typescript
import image from ohos.multimedia.image
let colorBuffer patch.buffer
let pixelmap await image.createPixelMap(colorBuffer, {size: {height: frame.dims.height as number,width: frame.dims.width as number}
})4. 高斯模糊
然后对PixelMap像素数据进行高斯模糊 调用 blur(pixelmap,10,true, (outPixelMap){ // 模糊后的pixelmap数据})在回调中获取模糊后的pixelmap。以下是模糊处理的算法
export async function blur(bitmap: any, radius: number, canReuseInBitmap: boolean, func: AsyncTransformPixelMap) {if (radius 1) {func(error,radius must be greater than 1 , null);return;}let imageInfo await bitmap.getImageInfo();let size {width: imageInfo.size.width,height: imageInfo.size.height}if (!size) {func(new Error(fastBlur The image size does not exist.), null)return;}let w size.width;let h size.height;var pixEntry: ArrayPixelEntry new Array()var pix: Arraynumber new Array()let bufferData new ArrayBuffer(bitmap.getPixelBytesNumber());await bitmap.readPixelsToBuffer(bufferData);let dataArray new Uint8Array(bufferData);for (let index 0; index dataArray.length; index4) {const r dataArray[index];const g dataArray[index1];const b dataArray[index2];const f dataArray[index3];let entry new PixelEntry();entry.a 0;entry.b b;entry.g g;entry.r r;entry.f f;entry.pixel ColorUtils.rgb(entry.r, entry.g, entry.b);pixEntry.push(entry);pix.push(ColorUtils.rgb(entry.r, entry.g, entry.b));}let wm w - 1;let hm h - 1;let wh w * h;let div radius radius 1;let r CalculatePixelUtils.createIntArray(wh);let g CalculatePixelUtils.createIntArray(wh);let b CalculatePixelUtils.createIntArray(wh);let rsum, gsum, bsum, x, y, i, p, yp, yi, yw: number;let vmin CalculatePixelUtils.createIntArray(Math.max(w, h));let divsum (div 1) 1;divsum * divsum;let dv CalculatePixelUtils.createIntArray(256 * divsum);for (i 0; i 256 * divsum; i) {dv[i](i / divsum);
}yw yi 0;let stack CalculatePixelUtils.createInt2DArray(div,3);let stackpointer, stackstart, rbs, routsum, goutsum, boutsum, rinsum, ginsum, binsum: number;let sir: Arraynumber;let r1 radius 1;
for(y 0; y h; y){rinsum ginsum binsum routsum goutsum boutsum rsum gsum bsum 0;
for(i -radius; i radius; i){p pix[yi Math.min(wm, Math.max(i,0))];sir stack[i radius];sir[0](p 0xff0000)16;sir[1](p 0x00ff00)8;sir[2](p 0x0000ff);rbs r1 - Math.abs(i);rsum sir[0]* rbs;gsum sir[1]* rbs;bsum sir[2]* rbs;
if(i 0){rinsum sir[0];ginsum sir[1];binsum sir[2];
}else{routsum sir[0];goutsum sir[1];boutsum sir[2];
}
}stackpointer radius;for(x 0; x w; x){r[yi] dv[rsum];g[yi] dv[gsum];b[yi] dv[bsum];rsum - routsum;gsum - goutsum;bsum - boutsum;stackstart stackpointer - radius div;sir stack[stackstart % div];routsum - sir[0];goutsum - sir[1];boutsum - sir[2];if(y 0){vmin[x] Math.min(x radius 1, wm);
}p pix[yw vmin[x]];sir[0](p 0xff0000)16;sir[1](p 0x00ff00)8;sir[2](p 0x0000ff);rinsum sir[0];ginsum sir[1];binsum sir[2];rsum rinsum;gsum ginsum;bsum binsum;stackpointer (stackpointer 1)% div;sir stack[(stackpointer)% div];routsum sir[0];goutsum sir[1];boutsum sir[2];rinsum - sir[0];ginsum - sir[1];binsum - sir[2];yi;
}yw w;
}
for(x 0; x w; x){rinsum ginsum binsum routsum goutsum boutsum rsum gsum bsum 0;yp -radius * w;
for(i -radius; i radius; i){yi Math.max(0, yp) x;sir stack[i radius];sir[0] r[yi];sir[1] g[yi];sir[2] b[yi];rbs r1 - Math.abs(i);rsum r[yi]* rbs;gsum g[yi]* rbs;bsum b[yi]* rbs;if(i 0){rinsum sir[0];ginsum sir[1];binsum sir[2];
}else{routsum sir[0];goutsum sir[1];boutsum sir[2];
}if(i hm){yp w;
}
}yi x;stackpointer radius;
for(y 0; y h; y){
// Preserve alpha channel: ( 0xff000000 pix[yi] )pix[yi](0xff000000 pix[Math.round(yi)])|(dv[Math.round(rsum)]16)|(dv[Math.round(gsum)]8)| dv[Math.round(bsum)];rsum - routsum;gsum - goutsum;bsum - boutsum;stackstart stackpointer - radius div;sir stack[stackstart % div];routsum - sir[0];goutsum - sir[1];boutsum - sir[2];if(x 0){vmin[y] Math.min(y r1, hm)* w;
}p x vmin[y];sir[0] r[p];sir[1] g[p];sir[2] b[p];rinsum sir[0];ginsum sir[1];binsum sir[2];rsum rinsum;gsum ginsum;bsum binsum;stackpointer (stackpointer 1)% div;sir stack[stackpointer];routsum sir[0];goutsum sir[1];boutsum sir[2];rinsum - sir[0];ginsum - sir[1];binsum - sir[2];yi w;
}
}let bufferNewData newArrayBuffer(bitmap.getPixelBytesNumber());let dataNewArray newUint8Array(bufferNewData);let index 0;for(let i 0; i dataNewArray.length; i 4){dataNewArray[i] ColorUtils.red(pix[index]);dataNewArray[i1] ColorUtils.green(pix[index]);dataNewArray[i2] ColorUtils.blue(pix[index]);dataNewArray[i3] pixEntry[index].f;index;
}await bitmap.writeBufferToPixels(bufferNewData);
if(func){
func(success, bitmap);
}
}如果需要高级滤镜效果可以参考ImageKnife组件的transform部分这里仅仅展示模糊效果。
由于滤镜效果目前ohos-gif-drawable三方库并没有开发接口提供出来所以开发者可以根据实际需求重写自定义组件GIFComponent.,只需要在生成PixelMap的代码片段中加入滤镜代码即可利用滤镜效果开发更多精彩的应用。
经常有很多小伙伴抱怨说不知道学习鸿蒙开发哪些技术不知道需要重点掌握哪些鸿蒙应用开发知识点
为了能够帮助到大家能够有规划的学习这里特别整理了一套纯血版鸿蒙HarmonyOS Next全栈开发技术的学习路线包含了鸿蒙开发必掌握的核心知识要点内容有ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、WebGL、元服务、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、OpenHarmony驱动开发、系统定制移植等等鸿蒙HarmonyOS NEXT技术知识点。 《鸿蒙 (Harmony OS)开发学习手册》共计892页:https://gitcode.com/HarmonyOS_MN/733GH/overview
如何快速入门
1.基本概念 2.构建第一个ArkTS应用 3.…… 开发基础知识:
1.应用基础知识 2.配置文件 3.应用数据管理 4.应用安全管理 5.应用隐私保护 6.三方应用调用管控机制 7.资源分类与访问 8.学习ArkTS语言 9.…… 基于ArkTS 开发
1.Ability开发 2.UI开发 3.公共事件与通知 4.窗口管理 5.媒体 6.安全 7.网络与链接 8.电话服务 9.数据管理 10.后台任务(Background Task)管理 11.设备管理 12.设备使用信息统计 13.DFX 14.国际化开发 15.折叠屏系列 16.…… 鸿蒙开发面试真题含参考答案:https://gitcode.com/HarmonyOS_MN/733GH/overview OpenHarmony 开发环境搭建 《OpenHarmony源码解析》:https://gitcode.com/HarmonyOS_MN/733GH/overview
搭建开发环境Windows 开发环境的搭建Ubuntu 开发环境搭建Linux 与 Windows 之间的文件共享……系统架构分析构建子系统启动流程子系统分布式任务调度子系统分布式通信子系统驱动子系统…… OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview