OpenHarmony轻松玩转GIF数据渲染

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小节主要是扩展讨论,如何添加滤镜效果和软解码遇到的耗时问题。

GIF_12">1.GIF的文件格式理论基础

工欲善其事必先利其器。首先我们需要为自己打下理论基础。了解GIF的数据格式,为后续解码GIF提供理论支持。

通过学习GIF的文件格式,我们对于GIF的组成格式有了一定的了解,并且有助于理解后面GIF的解码。

在开始介绍之前,我想让大家了解一下整体的结构思路如下图:

其中gifuct-js三方库主要完成了解码的工作。

ohos-gif-drawable三方库则是在gifuct-js的三方库之上,进行了封装。并结合了OpenHarmony的Canvas绘制能力,达到了播放和控制GIF的能力。

GIFgifuctjs_28">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库的基础使用简单介绍完了。

如何使用GIF:ohos-gif-drawable三方库的介绍。

我们先来看看整个ohos-gif-drawable组件的模型图,通过模型图,我们可以看到,用户只要关注GIFComponent组件,和GIFComponent.ControllerOptions配置参数以及控制参数autoPlay和resetGif即可,非常简单!

  1. 支持的功能列表如下

● 支持播放GIF图片。
● 支持控制GIF播放/暂停。
● 支持重置GIF播放动画。
● 支持调节GIF播放速率。
● 支持监听GIF所有帧显示完成后的回调。
● 支持设置显示大小。
● 支持7种不同的展示类型。
● 支持设置显示区域背景颜色。

  1. 如何使用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: AsyncTransform<PixelMap>) {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: Array<PixelEntry> = new Array()var pix: Array<number> = new Array()let bufferData = new ArrayBuffer(bitmap.getPixelBytesNumber());await bitmap.readPixelsToBuffer(bufferData);let dataArray = new Uint8Array(bufferData);for (let index = 0; index < dataArray.length; index+=4) {const r = dataArray[index];const g = dataArray[index+1];const b = dataArray[index+2];const f = dataArray[index+3];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: Array<number>;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[i+1]= ColorUtils.green(pix[index]);dataNewArray[i+2]= ColorUtils.blue(pix[index]);dataNewArray[i+3]= 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

图片

OpenHarmony 设备开发学习手册:https://gitcode.com/HarmonyOS_MN/733GH/overview

图片
在这里插入图片描述


http://www.ppmy.cn/news/1521326.html

相关文章

cad打印pdf很模糊怎么调清晰?2024教你快速进行文件格式转换方法合集

cad打印pdf很模糊怎么调清晰&#xff1f;2024教你快速进行文件格式转换方法合集 在使用CAD打印PDF时&#xff0c;输出的PDF文件如果模糊&#xff0c;通常是因为打印设置或者导出参数不正确。以下是五款软件和工具&#xff0c;能够帮助你调整CAD打印时的输出设置&#xff0c;从…

Qt 应用程序主界面

主要窗口类的概述 这些类提供了典型现代主应用程序窗口所需的一切&#xff0c;如主窗口本身、菜单和工具栏、状态栏等。 QAction 可以插入小部件的抽象用户界面操作 QActionGroup 将动作组合在一起 QDockWidget 小部件&#xff0c;可以停靠在QMainWindow中&#xff0c;也可以作…

黑马程序员Python数据挖掘|1Jupyter Notebook的使用

一 Jupyter Notebook介绍 二 为什么用Jupyter Notebook 1.在画图方面的优势 用 Jupyter Notebook &#xff1a; 方便进行数据的展示。 用 pycharm : 画完图后没有继续执行读取数据的代码&#xff0c;阻塞了。 把图片关掉才会继续执行代码。 2.在pycharm里如果读取很大的数据&…

优化器与现有网络模型的修改

一、优化器 optimizer optim.SGD(model.parameters(), lr0.01&#xff08;学习速率&#xff09;, momentum0.9) optimizer optim.Adam([var1, var2], lr0.0001) 一般&#xff0c;学习率的设置&#xff0c;先从大的设置&#xff0c;逐渐变小。 神经网络可以参见上篇文章&am…

oceanbase OBCE 第四章实验 事务与远程执行

实验环境&#xff1a;企业版V3 1-1-1 前期准备&#xff1a; 新建一个 oracle 租户 1C2GB 新建资源规格&#xff1a; create resource unit u1_ora max_cpu1,min_cpu1,max_memory2G,min_memory2G,max_iops128,max_disk_size10G,max_session_num100; 新建资源池&#xff1a; c…

【AI】 代码界的超级加速器!阿里云通义灵码让你工作效率飙升,编程就像开了挂一样!

文章目录 一、正文&#xff1a;二、核心场景代码智能生成研发智能问答 三、功能介绍行间代码生成研发智能问答编码问题解决企业级管理 结语相关链接&#xff1a; 一、正文&#xff1a; 在当今快节奏的软件开发领域&#xff0c;提高工作效率是每一位开发者不断追求的目标。 通义…

Vue:F11全屏模式状态监听,识别

本文将介绍如何在vue中实现按F11键后全屏模式的监听。 来回切换F11之后,控制台打印结果如下图所示, <script lang="ts" setup>import {ref, onMounted, onBeforeUnmount } from vue;

2024国赛数学建模ABC题思路模型

完整的思路模型请查看文末名片 完整的思路模型请查看文末名片 完整的思路模型请查看文末名片

sql-libs第三关详细解答

首先看看and 12会不会正常显示 结果正常显示&#xff0c;说明存在引号闭合 加了一个引号&#xff0c;发现报错信息中还存在括号&#xff0c;说明sql语句中有括号&#xff0c;那我们还要闭合括号 现在就好了&#xff0c;and 11正常&#xff0c;and 12不正常&#xff0c;那就开始…

AI科学家:自动化科研的未来之路

随着人工智能&#xff08;AI&#xff09;技术的不断进步&#xff0c;AI已经在众多领域中展现了强大的潜力&#xff0c;尤其是在科研方面的应用正在引起广泛关注。最近&#xff0c;Sakana AI与牛津大学和不列颠哥伦比亚大学联合推出了一款被称为“AI科学家”的自动化科研工具&am…

一文搞懂大数据流式计算引擎Flink【万字详解,史上最全】

往期推荐 一文入门大数据准流式计算引擎Spark【万字详解&#xff0c;全网最新】-CSDN博客 浅谈维度建模、数据分析模型&#xff0c;何为数据仓库&#xff0c;与数据库的区别_统一数仓 数据库用户名-CSDN博客数仓架构&#xff1a;离线数仓、实时数仓Lambda和Kappa、湖仓一体数据…

数据库水平分表方案

数据库分表有很多策略&#xff0c;如下&#xff1a; 数据库分表是处理大型数据库中数据量过大的一种常见策略&#xff0c;它可以提高查询性能、减少锁竞争、降低维护成本等。以下是一些常见的数据库分表方案&#xff1a; 1. **垂直分表&#xff08;Vertical Partitioning&…

2024年6月第2套英语四级真题PDF

2024年6月第2套英语四级真题PDF

使用matlab的热门问题

MATLAB广泛应用于科学计算、数据分析、信号处理、图像处理、机器学习等多个领域&#xff0c;因此热门问题也涵盖了这些方面。以下是一些可能被认为当前最热门的MATLAB问题&#xff1a; 深度学习与神经网络&#xff1a; 如何使用MATLAB的深度学习工具箱&#xff08;Deep Learni…

【SQL】统一字符格式

目录 语法 需求 示例 分析 代码 语法 substring(column_name, start, length)用于从一个字符串中提取子字符串 column_name&#xff08;或任何字符串表达式&#xff09;&#xff1a;这是要从中提取子字符串的列名或字符串表达式。start&#xff1a;这是子字符串开始的位置…

2024年高教杯国赛(C题)数学建模竞赛解题思路|完整代码论文集合

我是Tina表姐&#xff0c;毕业于中国人民大学&#xff0c;对数学建模的热爱让我在这一领域深耕多年。我的建模思路已经帮助了百余位学习者和参赛者在数学建模的道路上取得了显著的进步和成就。现在&#xff0c;我将这份宝贵的经验和知识凝练成一份全面的解题思路与代码论文集合…

vue 踩坑记录

本地开发没有cookie 解决方案 设置代理&#xff0c;并把changeOrigin设为true proxy的changeOrigin如果设置为false&#xff1a;请求头中host仍然是浏览器发送过来的host&#xff1b; 如果设置成true&#xff1a;发送请求头中host会设置成target。 允许axios请求携带cookie等凭…

如何在Mac电脑上本地部署Stable Diffusion:详细教程(webUI)

Stable Diffusion是一款强大的AI生成图像模型&#xff0c;它可以基于文本描述生成高质量的图像。对于想要在本地运行此模型的用户来说&#xff0c;使用Mac电脑部署Stable Diffusion是一个非常吸引人的选择&#xff0c;特别是对于M1或M2芯片的用户。本文将详细介绍如何在Mac上本…

香港一带一路研究院国际事务研究中心副主任陈景才阐述香港在一带一路建设及区块链金融领域的关键作用

2024年8月28日&#xff0c;香港金管局举行Ensemble项目沙盒&#xff08;以下简称沙盒&#xff09;启动仪式&#xff0c;并宣布首阶段试验将涵盖四大代币化资产用例主题&#xff0c;标志着金融业在代币化技术的实际应用进程中迈出重要一步。香港一带一路研究院国际事务研究中心副…

MySQL-35个DQL练手题(难)

第1题 取得每个部门最高薪水的人员名称 第一步&#xff1a;取得每个部门最高薪水 select max(sal) topsal, deptno from emp group by deptno;第二步&#xff1a;将上面第一步的查询结果当做一张临时表t&#xff0c;进行表连接&#xff0c;条件是&#xff1a;t.deptnoe.deptn…