7.服务卡片

1.什么是卡片

Form Kit(卡片开发服务)提供一种界面展示形式,可以将应用的重要信息或操作前置到服务卡片(以下简称“卡片”),以达到服务直达、减少跳转层级的体验效果。卡片常用于嵌入到其他应用(当前被嵌入方即卡片使用方只支持系统应用,例如桌面)中作为其界面显示的一部分,并支持拉起页面、发送消息等基础的交互能力。

2.卡片的一些配置参数

entry/src/main/resources/base/profile/form_config.json

3. 卡片的生命周期

//卡片生命周期
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';export default class EntryFormAbility extends FormExtensionAbility {// 	卡片被创建时触发onAddForm(want: Want) {// formBindingData:提供卡片数据绑定的能力,包括FormBindingData对象的创建、相关信息的描述// 获取卡片 IDconst formId = want.parameters && want.parameters['ohos.extra.param.key.form_identity'].toString()return formBindingData.createFormBindingData({title: '获取数据中~'});// Called to return a FormBindingData object.const formData = '';return formBindingData.createFormBindingData(formData);}// 卡片转换成常态卡片时触发onCastToNormalForm(formId: string) {// Called when the form provider is notified that a temporary form is successfully// converted to a normal form.}// 卡片被更新时触发(调用 updateForm 时)onUpdateForm(formId: string) {// Called to notify the form provider to update a specified form.}// 卡片发起特定事件时触发(message)onFormEvent(formId: string, message: string) {// Called when a specified message event defined by the form provider is triggered.}//卡片被卸载时触发onRemoveForm(formId: string) {// Called to notify the form provider that a specified form has been destroyed.}// 卡片状态发生改变时触发onAcquireFormState(want: Want) {// Called to return a {@link FormState} object.return formInfo.FormState.READY;}
}

4.卡片的通信

1.卡片之间通信

卡片在创建时,会触发onAddForm生命周期,此时返回数据可以直接传递给卡片

另外卡片在被卸载时,会触发onRemoveForm生命周期

1.卡片创建时传递数据

2.卡片向卡片的生命周期通信

卡片页面中可以通过postCardAction接口触发message事件拉起FormExtensionAbility中的onUpdateForm

onUpdateForm中通过updateForm来返回数据

const localStorage = new LocalStorage()
// 卡片组件通过LocalStorage来接收onAddForm中返回的数据
@Entry(localStorage)
@Component
struct WidgetCard {// 接收onAddForm中返回的卡片Id@LocalStorageProp("formId")formId: string = "xxx"
@LocalStorageProp('num')
num:number=0build() {Column() {Button(this.formId)Text(`${this.num}`).fontSize(15)Button('点击数字+100').onClick(() => {postCardAction(this, {action: 'message',// 提交过去的参数params: { num: this.num, aa: 200, formId: this.formId }})})}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}

记得要携带formId过去,因为返回数据时需要根据formId找到对应的卡片

//卡片生命周期
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
import { Want } from '@kit.AbilityKit';
import { JSON } from '@kit.ArkTS';export default class EntryFormAbility extends FormExtensionAbility {// 	卡片被创建时触发onAddForm(want: Want) {// formBindingData:提供卡片数据绑定的能力,包括FormBindingData对象的创建、相关信息的描述class FormData {// 每一张卡片创建时都会被分配一个唯一的idformId: string = want.parameters!['ohos.extra.param.key.form_identity'].toString();}let formData = new FormData()// console.log('测试',JSON.stringify(formData))// 返回数据给卡片return formBindingData.createFormBindingData(formData);}// 卡片转换成常态卡片时触发onCastToNormalForm(formId: string) {// Called when the form provider is notified that a temporary form is successfully// converted to a normal form.}// 卡片被更新时触发(调用 updateForm 时)onUpdateForm(formId: string) {// Called to notify the form provider to update a specified form.console.log('测试','卡片更新了')}// 卡片发起特定事件时触发(message)onFormEvent(formId: string, message: string) {//   接收到卡片通过message事件传递的数据// message {"num":0,"aa":200,"params":{"num":100,"aa":200},"action":"message"}interface IData {num: numberaa: number}interface IRes extends IData {params: IData,action: "message"formId: string}const params = JSON.parse(message) as IResconsole.log('测试',JSON.stringify(params))interface IRet {num: number}const data: IRet = {num: params.num + 100}const formInfo = formBindingData.createFormBindingData(data)console.log('测试',JSON.stringify(formInfo))// 返回数据给对应的卡片formProvider.updateForm(params.formId, formInfo)}//卡片被卸载时触发onRemoveForm(formId: string) {// Called to notify the form provider that a specified form has been destroyed.}// 卡片状态发生改变时触发onAcquireFormState(want: Want) {// Called to return a {@link FormState} object.return formInfo.FormState.READY;}
}

当卡片组件发起message事件时,我们可以通过onFormEvent监听到

数据接收要声明对应的接口

formProvider.updateForm(params.formId, formInfo)更新卡片

2.卡片与应用之间的通信

1.router 通信

router事件的特定是会拉起应用,前台会展示页面,会触发应用的onCreateonNewWant生命周期

我们可以利用这个特性做唤起特定页面并且传递数据。

当触发router事件时,

  1. 如果应用没有在运行,便触发 onCreate事件
  2. 如果应用正在运行,便触发onNewWant事件
const localStorage = new LocalStorage()
// 卡片组件通过LocalStorage来接收onAddForm中返回的数据
@Entry(localStorage)
@Component
struct WidgetCard {// 接收onAddForm中返回的卡片Id@LocalStorageProp("formId")formId: string = "xxx"
@LocalStorageProp('num')
num:number=0build() {Column() {//卡片与卡片的声明周期Button(this.formId)Text(`${this.num}`).fontSize(15)Button('点击数字+100').onClick(() => {postCardAction(this, {action: 'message',// 提交过去的参数params: { num: this.num, aa: 200, formId: this.formId }})})//router通信Button("跳转到主页").margin({top:10}).onClick(() => {postCardAction(this, {action: 'router',abilityName: 'EntryAbility', // 只能跳转到当前应用下的UIAbilityparams: {targetPage: 'pages-3路由与axios/Index',}});})}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}

解析传递过来的卡片 id 与卡片的参数

分别在应用的onCreate和onNewWant编写逻辑实现跳转页面

import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { display, router, window } from '@kit.ArkUI';
import { formInfo } from '@kit.FormKit';export default class EntryAbility extends UIAbility {// 要跳转的页面 默认是首页targetPage: string = "pages/Demo"onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {// 判断是否带有formId 因为我们直接点击图标,也会拉起应用,此时不会有formIdif (want.parameters && want.parameters[formInfo.FormParam.IDENTITY_KEY] !== undefined) {// 获取卡片的formIdconst formId = want.parameters![formInfo.FormParam.IDENTITY_KEY].toString();// 获取卡片传递过来的参数interface IData {targetPage: string}const params: IData = (JSON.parse(want.parameters?.params as string))console.log('测试','应用没有运行')this.targetPage = params.targetPage//   我们也可以在这里通过 updateForm(卡片id,数据) 来返回内容给卡片}}// 如果应用已经在运行,卡片的router事件不会再触发onCreate,会触发onNewWantonNewWant(want: Want, launchParam: AbilityConstant.LaunchParam): void {const formId = want.parameters![formInfo.FormParam.IDENTITY_KEY].toString();// 获取卡片传递过来的参数interface IData {targetPage: string}const params: IData = (JSON.parse(want.parameters?.params as string))this.targetPage = params.targetPageconsole.log('测试','应用已经在运行')// 跳转页面router.pushUrl({url: this.targetPage})//   我们也可以在这里通过 updateForm(卡片id,数据) 来返回内容给卡片}onDestroy(): void {hilog.info(0x0000, 'testTag', '%{public}s', 'Ability onDestroy');}onWindowStageCreate(windowStage: window.WindowStage): void {//模拟器启动windowStage.loadContent(this.targetPage, (err) => {console.log('测试',this.targetPage)});}onWindowStageDestroy(): void {// Main window is destroyed, release UI related resourceshilog.info(0x0000, 'testTag', '%{public}s', 'Ability onWindowStageDestroy');}onForeground(): void {// Ability has brought to foregroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');}onBackground(): void {// Ability has back to backgroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');}
}

2.call 通信

call会拉起应用,但是会在后台的形式运行。需要申请后台运行权限,可以进行比较耗时的任务

需要申请后台运行应用权限

{"module": {// ..."requestPermissions": [{"name": "ohos.permission.KEEP_BACKGROUND_RUNNING"}],
  1. 卡片组件触发call事件,参数中必须携带method属性,用来区分不同的方法
export const localStorage = new LocalStorage()@Entry(localStorage)
@Component
struct WidgetCard {// 接收onAddForm中返回的卡片Id@LocalStorageProp("formId")formId: string = "xxx"@LocalStorageProp("num")num: number = 100build() {Column() {Button("call事件" + this.num).onClick(() => {postCardAction(this, {action: 'call',abilityName: 'EntryAbility', // 只能跳转到当前应用下的UIAbilityparams: {// 如果事件类型是call,必须传递method属性,用来区分不同的事件method: "inc",formId: this.formId,num: this.num,}});})}.width("100%").height("100%").justifyContent(FlexAlign.Center)}
}
  1. 应用EntryAbility在onCreate中,通过 callee来监听不同的method事件
import { AbilityConstant, UIAbility, Want } from '@kit.AbilityKit';
import { hilog } from '@kit.PerformanceAnalysisKit';
import { router, window } from '@kit.ArkUI';
import { formBindingData, formInfo, formProvider } from '@kit.FormKit';
import { rpc } from '@kit.IPCKit';// 占位 防止语法出错,暂无实际作用
class MyParcelable implements rpc.Parcelable {marshalling(dataOut: rpc.MessageSequence): boolean {return true}unmarshalling(dataIn: rpc.MessageSequence): boolean {return true}
}export default class EntryAbility extends UIAbility {// 要跳转的页面 默认是首页targetPage: string = "pages/Index"onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {//   监听call事件中的特定方法this.callee.on("inc", (data: rpc.MessageSequence) => {// data中存放的是我们的参数params: {// 如果事件类型是call,必须传递method属性,用来区分不同的事件// method: "inc",// formId: this.formId,// num: this.num,interface IRes {formId: stringnum: number}// 读取参数const params = JSON.parse(data.readString() as string) as IResinterface IData {num: number}// 修改数据const info: IData = {num: params.num + 100}// 响应数据const dataInfo = formBindingData.createFormBindingData(info)formProvider.updateForm(params.formId, dataInfo)}// 防止语法报错,暂无实际应用return new MyParcelable()})}onWindowStageCreate(windowStage: window.WindowStage): void {// 跳转到对应的页面windowStage.loadContent(this.targetPage, (err) => {if (err.code) {return;}});}onForeground(): void {// Ability has brought to foregroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onForeground');}onBackground(): void {// Ability has back to backgroundhilog.info(0x0000, 'testTag', '%{public}s', 'Ability onBackground');}
}

5.卡片与图片的通信

1.传递本地图片

import { photoAccessHelper } from '@kit.MediaLibraryKit';
import { fileIo } from '@kit.CoreFileKit';
import { promptAction } from '@kit.ArkUI';@Entry
@Component
struct Index {async aboutToAppear() {//-------------------------------------------------------------- 1.初始化图片配置项// 创建一个新的 PhotoSelectOptions 实例来配置图片选择器的行为let PhotoSelectOptions = new photoAccessHelper.PhotoSelectOptions();// 设置 MIME 类型为图像类型,这样用户只能选择图像文件PhotoSelectOptions.MIMEType = photoAccessHelper.PhotoViewMIMETypes.IMAGE_TYPE;// 设置用户可以选择的最大图片数量为 1 张PhotoSelectOptions.maxSelectNumber = 1;//----------------------------------------------------------- 2.打开图片选择器,拿到图片// 创建一个新的 PhotoViewPicker 实例,用于打开图片选择器let photoPicker = new photoAccessHelper.PhotoViewPicker();// 使用前面配置好的选项打开图片选择器,并等待用户完成选择// 注意这里的 select 方法是一个异步方法,所以需要使用 await 关键字等待其结果const PhotoSelectResult = await photoPicker.select(PhotoSelectOptions);// 获取用户选择的第一张图片的 URI(统一资源标识符)// 假设这里只关心用户选择的第一张图片// uri file://media/Photo/3/IMG_1729864738_002/screenshot_20241025_215718.jpgconst uri = PhotoSelectResult.photoUris[0];promptAction.showToast({ message: `${uri}` })//------------------------------------------------------------- 3.拷贝图片到临时目录// 获取应用的临时目录let tempDir = getContext(this).getApplicationContext().tempDir;// 生成一个新的文件名const fileName = 123 + '.png'// 通过缓存路径+文件名 拼接出完整的路径const copyFilePath = tempDir + '/' + fileName// 将文件 拷贝到 临时目录const file = fileIo.openSync(uri, fileIo.OpenMode.READ_ONLY)fileIo.copyFileSync(file.fd, copyFilePath)}build() {RelativeContainer() {}.height('100%').width('100%')}
}

一旦保存到本地缓存除非卸载应用不然就一直有的

import { Want } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
import { formBindingData, FormExtensionAbility } from '@kit.FormKit';export default class EntryFormAbility extends FormExtensionAbility {// 在添加卡片时,打开一个本地图片并将图片内容传递给卡片页面显示onAddForm(want: Want): formBindingData.FormBindingData {// 假设在当前卡片应用的tmp目录下有一个本地图片 123.pnglet tempDir = this.context.getApplicationContext().tempDir;let imgMap: Record<string, number> = {};// 打开本地图片并获取其打开后的fdlet file = fileIo.openSync(tempDir + '/' + '123.png');//file.fd 打开的文件描述符。imgMap['imgBear'] = file.fd;class FormDataClass {// 卡片需要显示图片场景, 必须和下列字段formImages 中的key 'imgBear' 相同。imgName: string = 'imgBear';// 卡片需要显示图片场景, 必填字段(formImages 不可缺省或改名), 'imgBear' 对应 fdformImages: Record<string, number> = imgMap;}let formData = new FormDataClass();console.log("formDataformData", JSON.stringify(formData))// 将fd封装在formData中并返回至卡片页面return formBindingData.createFormBindingData(formData);}
}
let storageWidgetImageUpdate = new LocalStorage();@Entry(storageWidgetImageUpdate)
@Component
struct WidgetCard {@LocalStorageProp('imgName') imgName: ResourceStr = "";build() {Column() {Text(this.imgName)}.width('100%').height('100%').backgroundImage('memory://' + this.imgName).backgroundImageSize(ImageSize.Cover)}
}

Image组件通过入参(memory://fileName)中的(memory://)标识来进行远端内存图片显示,其中fileName需要和EntryFormAbility传递对象('formImages': {key: fd})中的key相对应。

2.传递网络图片

import { Want } from '@kit.AbilityKit';
import { fileIo } from '@kit.CoreFileKit';
import { formBindingData, FormExtensionAbility, formInfo, formProvider } from '@kit.FormKit';
import { http } from '@kit.NetworkKit';
import { BusinessError } from '@kit.BasicServicesKit';export default class EntryFormAbility extends FormExtensionAbility {// 将网络图片传递给onAddForm(want: Want) {// 注意:FormExtensionAbility在触发生命周期回调时被拉起,仅能在后台存在5秒// 建议下载能快速下载完成的小文件,如在5秒内未下载完成,则此次网络图片无法刷新至卡片页面上const formId = want.parameters![formInfo.FormParam.IDENTITY_KEY] as string// 需要在此处使用真实的网络图片下载链接let netFile ='https://env-00jxhf99mujs.normal.cloudstatic.cn/card/3.webp?expire_at=1729871552&er_sign=0eb3f6ac3730703039b1565b6d3e59ad'; let httpRequest = http.createHttp()// 下载图片httpRequest.request(netFile).then(async (data) => {if (data?.responseCode == http.ResponseCode.OK) {// 拼接图片地址let tempDir = this.context.getApplicationContext().tempDir;let fileName = 'file' + Date.now();let tmpFile = tempDir + '/' + fileName;let imgMap: Record<string, number> = {};class FormDataClass {// 卡片需要显示图片场景, 必须和下列字段formImages 中的key fileName 相同。imgName: string = fileName;// 卡片需要显示图片场景, 必填字段(formImages 不可缺省或改名), fileName 对应 fdformImages: Record<string, number> = imgMap;}// 打开文件let imgFile = fileIo.openSync(tmpFile, fileIo.OpenMode.READ_WRITE | fileIo.OpenMode.CREATE);imgMap[fileName] = imgFile.fd;// 写入文件await fileIo.write(imgFile.fd, data.result as ArrayBuffer);let formData = new FormDataClass();let formInfo = formBindingData.createFormBindingData(formData);// 下载完网络图片后,再传递给卡片formProvider.updateForm(formId, formInfo)fileIo.closeSync(imgFile);httpRequest.destroy();console.log("============")}}).catch((e: BusinessError) => {console.log("eeee", e.message)})class FormData {formId: string = ""}// 先返回基本数据return formBindingData.createFormBindingData(new FormData);}onFormEvent(formId: string, message: string): void {}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/news/903568.shtml
繁体地址,请注明出处:http://hk.pswp.cn/news/903568.shtml
英文地址,请注明出处:http://en.pswp.cn/news/903568.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

探索目标检测:边界框与锚框的奥秘

笔者在2022年开始学习目标检测的时候&#xff0c;对各种框的概念那是相当混淆&#xff0c;比如&#xff1a; 中文名词&#xff1a;边界框、锚框、真实框、预测框等英文名词&#xff1a;BoundingBox、AnchorBox、Ground Truth等 同一个英文名词比如BoundingBox翻译成中文也有多个…

[原创](现代Delphi 12指南):[macOS 64bit App开发]: [1]如何使用原生NSAlert消息框 (runModal模式)

[作者] 常用网名: 猪头三 出生日期: 1981.XX.XX 企鹅交流: 643439947 个人网站: 80x86汇编小站 编程生涯: 2001年~至今[共24年] 职业生涯: 22年 开发语言: C/C++、80x86ASM、Object Pascal、Objective-C、C#、R、Python、PHP、Perl、 开发工具: Visual Studio、Delphi、XCode、…

LangChain的向量RAG与MCP在意图识别的主要区别

LangChain的向量RAG与MCP在意图识别实现上的区别主要体现在技术路径、流程设计以及应用场景三个方面&#xff1a; 1. 技术路径差异 LangChain向量RAG 语义相似度驱动&#xff1a;通过用户输入的原始查询与向量化知识库的语义匹配实现意图识别。例如&#xff0c;用户提问"…

[特殊字符] Spring Cloud 微服务配置统一管理:基于 Nacos 的最佳实践详解

在微服务架构中&#xff0c;配置文件众多、管理复杂是常见问题。本文将手把手演示如何将配置集中托管到 Nacos&#xff0c;并在 Spring Cloud Alibaba 项目中实现统一配置管理 自动刷新机制。 一、为什么要使用 Nacos 统一配置&#xff1f; 传统方式下&#xff0c;每个服务都…

2025平航杯—团队赛

2025平航杯团队赛 计算机取证 分析起早王的计算机检材&#xff0c;起早王的计算机插入过USB序列号是什么(格式&#xff1a;1)分析起早王的计算机检材&#xff0c;起早王的便签里有几条待干(格式&#xff1a;1)分析起早王的计算机检材&#xff0c;起早王的计算机默认浏览器是什…

JSON-RPC 2.0 规范中文版——无状态轻量级远程过程调用协议

前言 JSON-RPC是一种简单、轻量且无状态的远程过程调用&#xff08;RPC&#xff09;协议&#xff0c;它允许不同系统通过标准化的数据格式进行通信。自2010年由JSON-RPC工作组发布以来&#xff0c;已成为众多应用中实现远程交互的基础协议之一。本规范主要表达了JSON-RPC 2.0版…

微控制器编程 | ISP、IAP 与 ICP 的原理与比较

注&#xff1a;英文引文&#xff0c;机翻未校。 图片清晰度限于引文原状。 Introduction to Programming of Microcontroller: ISP, IAP and ICP 微控制器编程介绍&#xff1a;ISP、IAP 和 ICP Date: 30-11-2022 1. What is Microcontroller Programming 什么是微控制器编…

Allegro23.1新功能之新型via structure创建方法操作指导

Allegro23.1新功能之新型via structure创建方法操作指导 Allegro升级到了23.1后,支持创建新型via structure 通过直接定义参数来生成 具体操作如下 打开软件,选择 Allegro PCB Designer

IBM WebSphere Application Server 7.0/8.5.5证书过期问题处理

证书过期错误日志&#xff1a; [3/14/16 7:22:20:332 PDT] 0000007d WSX509TrustMa E CWPKI0312E: The certificate with subject DN CNMXSYSTEMS, OUctgNodeCell01, OUctgNode01, OIBM, CUS has an end date Mon Jan 11 11:17:18 PST 2016 which is no longer valid. [3/14/…

select,poll,epoll区别联系

selsect,poll,epoll区别联系 目录 一、区别 二、联系 select、poll 和 epoll 都是在 Linux 系统中用于实现 I/O 多路复用的机制&#xff0c;它们的主要目的是让程序能够同时监控多个文件描述符&#xff0c;以判断是否有事件发生&#xff0c;从而提高 I/O 操作的效率。 一、区…

curl和wget的使用介绍

目录 一、curl 和 wget 区别 二、wget的使用 2.1 参数说明 2.2 wget 使用示例 三、curl的使用 3.1 参数说明 3.2 curl使用示例 一、curl 和 wget 区别 wget 和 curl 都可以下载内容。它们都可以向互联网发送请求并返回请求项&#xff0c;可以是文件、图片或者是其他诸如…

日语学习-日语知识点小记-构建基础-JLPT-N4阶段(12): ておき ます

日语学习-日语知识点小记-构建基础-JLPT-N4阶段&#xff08;12&#xff09;&#xff1a; ておき ます。 1、前言&#xff08;1&#xff09;情况说明&#xff08;2&#xff09;工程师的信仰 2、知识点&#xff08;1&#xff09;&#xff5e;ておき ます。&#xff08;2&#x…

高质量水火焰无损音效包

今天设计宝藏给大家分享的是Cinematic Elements: Fire & Water音频资源库包含大量高质量的火焰和水的声音效果。它具有非常强烈的个性特征和次世代的音效。火焰和水是两个令人印象深刻而 interessing 的元素。它们的表现形式从微小无害到巨大毁灭性都有。因此,它们的声音特…

毕业论文 | 传统特征点提取算法与匹配算法对比分析

传统特征点提取算法与匹配算法对比分析 一、特征点提取算法对比二、特征匹配算法对比三、核心算法原理与公式1. **Harris角点检测**2. **SIFT描述子生成**3. **ORB描述子**四、完整Matlab代码示例1. **Harris角点检测与匹配**2. **SIFT特征匹配(需VLFeat库)**3. **ORB特征匹配…

【网络原理】从零开始深入理解HTTP的报文格式(二)

本篇博客给大家带来的是网络HTTP协议的知识点, 续上篇文章,接着介绍HTTP的报文格式. &#x1f40e;文章专栏: JavaEE初阶 &#x1f680;若有问题 评论区见 ❤ 欢迎大家点赞 评论 收藏 分享 如果你不知道分享给谁,那就分享给薯条. 你们的支持是我不断创作的动力 . 王子,公主请阅…

Microsoft .NET Framework 3.5 离线安装包 下载

Microsoft. NET Framework 3.5 是支持生成和运行下一代应用程序和XML Web Services 的内部Windows 组件&#xff0c; 对 .NET Framework 2.0 和 3.0 中的许多新功能进行了更新和增补&#xff0c; 且附带了 .NET Framework 2.0 Service Pack 1 和 .NET Framework 3.0 Service…

Flask + ajax上传文件(三)--图片上传与OCR识别

本教程将详细介绍如何使用Flask框架构建一个图片上传与文字识别(OCR)的Web应用。我们将使用EasyOCR作为OCR引擎,实现一个支持中文和英文识别的完整应用。 环境准备 首先,确保你已经安装了Python 3.7+环境,然后安装必要的依赖库: pip install flask easyocr pillow werkz…

模型部署技巧(一)

模型部署技巧&#xff08;一&#xff09; 以下内容是参考CUDA与TensorRT模型部署内容第六章&#xff0c;主要针对图像的前/后处理中的trick。 参考&#xff1a; 1.部署分类器-int8-calibration 2. cudnn安装地址 3. 如何查找Tensor版本&#xff0c;与cuda 和 cudnn匹配 4. ti…

MySQL--数据引擎详解

存储引擎 MySQL体系结构 连接层&#xff1a; 主要接收客户端的连接&#xff0c;然后完成一些链接的处理&#xff0c;以及认证授权的相关操作和安全方案&#xff0c;还要去检查是否超过最大连接数等等&#xff0c;比如在连接MySQL服务器时需要输入用户名&#xff0c;密码&#…

【含文档+PPT+源码】基于微信小程序的健康饮食食谱推荐平台的设计与实现

项目介绍 本课程演示的是一款基于微信小程序的健康饮食食谱推荐平台的设计与实现&#xff0c;主要针对计算机相关专业的正在做毕设的学生与需要项目实战练习的 Java 学习者。 1.包含&#xff1a;项目源码、项目文档、数据库脚本、软件工具等所有资料 2.带你从零开始部署运行本…